OverviewFilesCommitsIssuesDocsReleasesPeers

keet-cli / keet-core-4.14.4-pretty / lib / core / contract / identity / private.js

355 lines · javascript ref:
const e = require("b4a"),
  {
    contract: {
      hyperschema: { encode: t },
    },
  } = require("../../../../schema/spec"),
  {
    verifyAttestation: i,
    verifyDeviceResponse: a,
    decryptContactRequest: s,
    generateMailboxKeyPair: r,
    generateRoomCapabilities: o,
  } = require("../../invitations"),
  n = require("../registration"),
  { KeetContractError: c } = require("../errors"),
  { isMemberActive: d, getMemberForDeviceKey: y } = require("../query"),
  {
    profileRoomStats: l,
    profileContactStats: u,
    profileContactRequestStats: m,
  } = require("../stats/profile"),
  { isValidBuildType: k } = require("../helpers"),
  p = ["isActive", "isFullyMuted", "isMentionsOnlyMuted", "isFavorite"],
  v = { IsActive: 1, IsFullyMuted: 2, IsMentionsOnlyMuted: 3, IsFavorite: 4 },
  w = ["isBlocked"],
  f = { IsBlocked: 1 },
  b = ["isPending", "isAccepted", "isRejected", "isDiscarded", "isSeen"],
  g = { IsPending: 1, IsAccepted: 2, IsRejected: 3, IsDiscarded: 4, IsSeen: 5 }
async function K({ sharedRooms: e, blockedContacts: t }, { db: i, writer: a }) {
  const [s, r] = await Promise.all([y(i, a.key), i.get("@keet-private-id/counters")])
  if (!d(s)) throw c.ABORT()
  for (let t = 0; t < e.length; t++) {
    const { roomKey: a, initiator: s, fastForwardTo: r, encryptionKey: n, seed: c } = e[t],
      d = {
        roomKey: a,
        encryptionKey: n,
        mailbox: o(a, c).mailboxKeyPair.publicKey,
        clock: t + 1,
        status: { isActive: !0, isFullyMuted: !1, isMentionsOnlyMuted: !1 },
        initiator: s,
        fastForwardTo: r,
        identitySwap: null,
      }
    await i.insert("@keet-private-id/rooms", d)
  }
  for (let e = 0; e < t.length; e++) {
    const a = r ? r.contacts + 1 : 0,
      s = { memberKey: t[e], clock: a, status: { isBlocked: !0 }, mailbox: null, roomKey: null }
    await i.insert("@keet-private-id/contacts", s)
  }
}
async function A({ identity: t }, { db: i, writer: a }) {
  const [s, r] = await Promise.all([y(i, a.key), i.get("@keet-private-id/identity")])
  if (!d(s) || !r || !e.equals(t.publicKey, r.publicKey)) throw c.ABORT()
  ;(t.discoveryCoreKey && (r.discoveryCoreKey = t.discoveryCoreKey),
    await i.insert("@keet-private-id/identity", r))
}
async function R({ key: e, settings: t }, { db: i, writer: a }) {
  const [s, r] = await Promise.all([y(i, a.key), i.get("@keet-private-id/settings")])
  if (!d(s)) throw c.ABORT()
  const o = { ...r, [e]: t[e] }
  await i.insert("@keet-private-id/settings", o)
}
async function h({ invitation: e }, { db: t, writer: i }) {
  const [a, s] = await Promise.all([y(t, i.key), t.get("@keet/system-digest")])
  if (!d(a)) throw c.ABORT()
  const r = s.settings.buildType,
    o = e.buildType
  if (!k(r, o)) throw c.INVALID_BUILD_TYPE()
  await t.insert("@keet-private-id/pending-invitations", e)
}
async function O({ id: e }, { db: t, writer: i }) {
  const a = await y(t, i.key)
  if (!d(a)) throw c.ABORT()
  await t.delete("@keet-private-id/pending-invitations", { id: e })
}
async function T({ blindResponse: t }, { db: i, writer: s, hostcalls: o }) {
  const n = await i.get("@keet/room-capabilities")
  if (!n) throw c.ABORT()
  let d = null
  try {
    const e = r(o.key, n.seed)
    d = a(e, t)
  } catch (e) {
    throw c.ABORT()
  }
  if (!d) throw c.ABORT()
  const { id: y, response: u } = d,
    { roomKeys: m } = u
  if (!m.key || !m.encryptionKey) throw c.ABORT()
  const [k, p, v, w] = await Promise.all([
    i.get("@keet-private-id/pending-invitations", { id: y }),
    i.get("@keet-private-id/rooms", { roomKey: m.key }),
    i.get("@keet-private-id/counters"),
    i.get("@keet/system-digest"),
  ])
  if (!k) throw c.ABORT()
  const f = v ? v.rooms + 1 : 0,
    b = p
  let g = p
  if (
    (g
      ? (!g.status.isActive || w.abi.version >= 12) &&
        ((g.clock = f), (g.status.isActive = !0), (g.status.isReadOnly = !1))
      : (g = {
          clock: f,
          roomKey: m.key,
          encryptionKey: m.encryptionKey,
          fastForwardTo: m.fastForwardTo,
          status: { isActive: !0, isReadOnly: !1 },
          initiator: k.initiator,
          mailbox: k.mailbox,
          identitySwapV2: k.identity,
        }),
    await i.insert("@keet-private-id/rooms", g),
    await l(i, g, b),
    w.abi.version < 11)
  )
    await i.delete("@keet-private-id/pending-invitations", { id: y })
  else
    for await (const t of i.find("@keet-private-id/pending-invitations"))
      e.equals(t.mailbox, g.mailbox) && (await i.delete("@keet-private-id/pending-invitations", t))
  await o.ackWriter(s.key)
}
async function B({ header: e, ...t }, { db: i, writer: a }) {
  const [s, r, o, n, u] = await Promise.all([
    y(i, a.key),
    i.get("@keet-private-id/rooms", { roomKey: t.roomKey }),
    i.get("@keet-private-id/stats"),
    i.get("@keet-private-id/counters"),
    i.get("@keet/system-digest"),
  ])
  if (!u || !d(s)) throw c.ABORT()
  const m = r
  let k = 0
  u.abi.version < 10 ? (r ? (k = r.clock) : o && (k = o.rooms + 1)) : n && (k = n.rooms + 1)
  let p = r?.status.isReadOnly
  !p && t.isReadOnly && (p = !0)
  const v = { ...t, clock: k, status: { isActive: !0, isReadOnly: p }, contact: t.dm }
  ;(await i.insert("@keet-private-id/rooms", v), await l(i, v, m))
}
async function q({ roomKey: e }, { db: t, writer: i }) {
  const a = await y(t, i.key)
  if (d(a)) return t.delete("@keet-private-id/rooms", { roomKey: e })
}
async function P({ header: t, roomKey: i, key: a, status: s }, { db: r, writer: o }) {
  const [n, u, m, k] = await Promise.all([
    y(r, o.key),
    r.get("@keet-private-id/rooms", { roomKey: i }),
    r.get("@keet-private-id/counters"),
    r.get("@keet/system-digest"),
  ])
  if (!d(n) || !u) throw c.ABORT()
  if (!L(a)) throw c.ABORT()
  const p = u,
    v = E(a),
    w = m.rooms + 1
  if (
    ((u.status = { ...u.status, [v]: s[v] }),
    (u.clock = w),
    !u.status.isActive && k.abi.version >= 12)
  )
    for await (const t of r.find("@keet-private-id/pending-invitations"))
      e.equals(t.mailbox, u.mailbox) && (await r.delete("@keet-private-id/pending-invitations", t))
  ;(await r.insert("@keet-private-id/rooms", u), await l(r, u, p))
}
async function x(
  { contact: { memberKey: e, mailbox: t, roomKey: i, status: a } },
  { db: s, writer: r },
) {
  const [o, n, l] = await Promise.all([
    y(s, r.key),
    s.get("@keet-private-id/contacts", { memberKey: e }),
    s.get("@keet-private-id/counters"),
  ])
  if (!d(o)) throw c.ABORT()
  const m = n,
    k = l ? l.contacts + 1 : 0
  let p = n
  ;(p
    ? ((p.mailbox = t), (p.status = a), (p.clock = k))
    : (p = { memberKey: e, mailbox: t, status: a, clock: k }),
    await s.insert("@keet-private-id/contacts", p),
    await u(s, p, m))
}
async function I({ memberKey: e, key: t, status: i }, { db: a, writer: s }) {
  const [r, o, n] = await Promise.all([
    y(a, s.key),
    a.get("@keet-private-id/contacts", { memberKey: e }),
    a.get("@keet-private-id/counters"),
  ])
  if (!d(r) || !o) throw c.ABORT()
  if (!_(t)) throw c.ABORT()
  const l = o,
    m = W(t)
  ;((o.status = { ...o.status, [m]: i[m] }),
    (o.clock = n ? n.contacts + 1 : 0),
    await a.insert("@keet-private-id/contacts", o),
    await u(a, o, l))
}
async function S({ memberKey: e }, { db: t, writer: i }) {
  const [a, s] = await Promise.all([
    y(t, i.key),
    t.get("@keet-private-id/contacts", { memberKey: e }),
  ])
  if (!d(a) || !s) throw c.ABORT
  await t.delete("@keet-private-id/contacts", s)
}
async function M({ blindRequest: e, header: a }, { db: o, hostcalls: n, writer: d }) {
  const y = await o.get("@keet/room-capabilities")
  if (!y) throw c.ABORT()
  let l = null
  try {
    const t = r(n.key, y.seed)
    l = s(t, e)
  } catch (e) {
    throw c.ABORT()
  }
  if (!l) throw c.ABORT()
  const { body: u, attestation: k } = l,
    { sender: p, keys: v, mailbox: w, message: f } = u,
    [b, g, K] = await Promise.all([
      o.get("@keet-private-id/contacts", { memberKey: p.attestation.memberKey }),
      o.get("@keet-private-id/stats"),
      o.get("@keet/system-digest"),
    ])
  if (b && b.status.isBlocked) throw c.ABORT()
  if (b && b.roomKey && K.abi.version < 12) throw c.ABORT()
  const A = t("@keet-private-id/contact-request-body", u),
    R = t("@keet/member-profile", p.profile)
  if (!i(k, A)) throw c.ABORT()
  if (!i(p.attestation, R)) throw c.ABORT()
  let h = !0
  const O = a.timestamp,
    T = o.find("@keet-private-id/pending-contact-requests-by-member", {
      gte: { memberKey: p.attestation.memberKey },
      lte: { memberKey: p.attestation.memberKey },
    })
  for await (const e of T)
    e.sentAt > O
      ? (h = !1)
      : ((e.status.isPending = !1),
        (e.status.isDiscarded = !0),
        await o.insert("@keet-private-id/contact-requests-v2", e))
  if (!h) return
  const B = g?.contactRequests || 0,
    q = {
      memberKey: p.attestation.memberKey,
      sender: p.profile,
      status: { isPending: !0 },
      clock: B,
      keys: v,
      mailbox: w,
      message: f,
      sentAt: O,
    }
  ;(await o.insert("@keet-private-id/contact-requests-v2", q),
    await m(o, q, null),
    await n.ackWriter(d.key))
}
async function C({ memberKey: e, roomKey: t, key: i, status: a }, { db: s, writer: r }) {
  if (!t) throw c.ABORT()
  const [o, n, m] = await Promise.all([
    y(s, r.key),
    s.get("@keet-private-id/contact-requests-v2", { memberKey: e, keys: { key: t } }),
    s.get("@keet-private-id/counters"),
  ])
  if (!d(o) || !n) throw c.ABORT()
  if (!U(i)) throw c.ABORT()
  const k = N(i),
    p = n.sender,
    v = !n.status.isAccepted && i === g.IsAccepted,
    w = i === g.IsSeen
  if (!w && n.status.isAccepted) throw c.ABORT()
  const f = {
      isPending: !1,
      isAccepted: !1,
      isRejected: !1,
      isDiscarded: !1,
      isSeen: n.status.isSeen,
    },
    b = w ? n.status : f
  if (
    ((n.status = { ...b, [k]: a[k] }),
    (n.status.isAccepted || n.status.isRejected || n.status.isDiscarded) &&
      (n.status.isPending = !1),
    await s.insert("@keet-private-id/contact-requests-v2", n),
    !v)
  )
    return
  const K = (m?.rooms || 0) + 1,
    A = (m?.contacts || 0) + 1,
    R = {
      clock: K,
      roomKey: n.keys.key,
      encryptionKey: n.keys.encryptionKey,
      mailbox: n.mailbox,
      status: { isActive: !0 },
    },
    h = { memberKey: n.memberKey, mailbox: p.mailbox, clock: A, status: { isBlocked: !1 } }
  ;(await s.insert("@keet-private-id/rooms", R),
    await l(s, R, null),
    await s.insert("@keet-private-id/contacts", h),
    await u(s, h, null))
}
async function F({ memberKey: e }, { db: t, writer: i }) {}
async function D({ key: e }, { db: t, writer: i }) {
  const a = await y(t, i.key)
  if (!d(a)) throw c.ABORT()
  await t.insert("@keet-private-id/unreads-v2", { deviceKey: i.key, key: e })
}
async function j({ key: e }, { db: t, writer: i }) {
  const a = await y(t, i.key)
  if (!d(a)) throw c.ABORT()
  await t.delete("@keet-private-id/unreads-v2", { deviceKey: i.key, key: e })
}
function V(e) {
  ;(e.add("@keet-private-id/run-v3-migration", K),
    e.add("@keet-private-id/update-identity", A),
    e.add("@keet-private-id/update-settings", R),
    e.add("@keet-private-id/add-room", B),
    e.add("@keet-private-id/remove-room", q),
    e.add("@keet-private-id/update-room-status", P),
    e.add("@keet-private-id/add-pending-invitation", h),
    e.add("@keet-private-id/remove-pending-invitation", O),
    e.add("@keet-private-id/resolve-pending-invitation", T),
    e.add("@keet-private-id/add-contact", x),
    e.add("@keet-private-id/update-contact-status", I),
    e.add("@keet-private-id/remove-contact", S),
    e.add("@keet-private-id/add-contact-request", M),
    e.add("@keet-private-id/update-contact-request-status", C),
    e.add("@keet-private-id/activate-contact-room", F),
    e.add("@keet-private-id/add-unreads-key", D),
    e.add("@keet-private-id/remove-unreads-key", j))
}
function E(e) {
  return p[e - 1]
}
function L(e) {
  return e >= 1 && e <= p.length
}
function W(e) {
  return w[e - 1]
}
function _(e) {
  return e >= 1 && e <= w.length
}
function N(e) {
  return b[e - 1]
}
function U(e) {
  return e >= 1 && e <= b.length
}
module.exports = { [n]: V, RoomStatus: v, ContactStatus: f, ContactRequestStatus: g }