OverviewFilesCommitsIssuesDocsReleasesPeers

favela-gateway / lib / bsky-bind.js

29 lines · javascript ref:
// bsky-bind.js — is this fronted DID a favela identity's, by BOTH sides' word? (hyper-social #82, I2a / D4a)
//
// ⛔ TWO-SIDED, OR NOT AT ALL. The DID's repo, signed by the DID key, names a favela feed (`net.favela.feed/self`,
// written by favela-bridge's projection); AND that feed's reach/self, written by the identity's own devices, names
// the DID as its credential. Either half alone is a claim anyone can make. Only the pair binds, and only a binding
// lets bsky interactions on the DID reach that identity's observation feed.
//
// PURE + INJECTED: `front` is the membrane's front for the DID (getRecord), `feedOf(feedKey)` the held favela feed or
// null. A failed read is a refusal, never a throw — the caller re-evaluates on the next change.

export const FEED_CLAIM = 'net.favela.feed'

export async function bindDid (did, { front, feedOf } = {}) {
  let rec = null
  try { rec = front && typeof front.getRecord === 'function' ? await front.getRecord(FEED_CLAIM, 'self') : null } catch { return { refused: 'could not read the DID repo' } }
  const feed = rec && rec.value && typeof rec.value.feed === 'string' ? rec.value.feed.toLowerCase() : null
  if (!feed) return { refused: 'the DID names no favela feed' }
  if (!/^[0-9a-f]{64}$/.test(feed)) return { refused: 'the DID names a malformed feed key' }
  let held = null
  try { held = feedOf ? await feedOf(feed) : null } catch { held = null }
  if (!held || typeof held.reach !== 'function') return { refused: 'that feed is not held here' }
  let reach = null
  try { reach = await held.reach() } catch { return { refused: 'could not read that feed\'s reach' } }
  if (!reach || reach.credential !== did) return { refused: 'that feed does not name this DID' }
  return { did, feed }
}

export default { bindDid, FEED_CLAIM }