OverviewFilesCommitsIssuesDocsReleasesPeers

autobase-doctor / node_modules / autobase / lib / boot.js

162 lines · javascript ref:
const c = require('compact-encoding')
const encryptionEncoding = require('encryption-encoding')
const messages = require('./messages.js')

module.exports = async function boot(
  corestore,
  key,
  { encrypt, encryptionKey, keyPair, exclusive = true, blindEncryption } = {}
) {
  const result = {
    key: null,
    local: null,
    bootstrap: null,
    encryptionKey: null,
    boot: null
  }

  const manifest = keyPair
    ? { version: corestore.manifestVersion, signers: [{ publicKey: keyPair.publicKey }] }
    : null

  if (key) {
    result.key = key

    const bootstrap = corestore.get({ key, active: false, valueEncoding: messages.OplogMessage })
    await bootstrap.ready()

    const localKey = await bootstrap.getUserData('autobase/local')

    if (keyPair) {
      result.local = corestore.get({
        keyPair,
        active: false,
        exclusive,
        valueEncoding: messages.OplogMessage,
        manifest
      })
    } else {
      if (bootstrap.writable && !localKey) {
        result.local = bootstrap.session({
          active: false,
          exclusive,
          valueEncoding: messages.OplogMessage
        })
      } else {
        const local = localKey
          ? corestore.get({
              key: localKey,
              active: false,
              exclusive,
              valueEncoding: messages.OplogMessage
            })
          : corestore.get({
              name: 'local',
              active: false,
              exclusive,
              valueEncoding: messages.OplogMessage
            })

        await local.ready()
        result.local = local
      }
    }

    result.bootstrap = bootstrap
  } else {
    result.local = keyPair
      ? corestore.get({
          keyPair,
          manifest,
          active: false,
          exclusive,
          valueEncoding: messages.OplogMessage
        })
      : corestore.get({
          name: 'local',
          active: false,
          exclusive,
          valueEncoding: messages.OplogMessage
        })
    await result.local.ready()

    const key = await result.local.getUserData('referrer')
    if (key) {
      result.key = key
      result.bootstrap = corestore.get({ key, active: false, valueEncoding: messages.OplogMessage })
      await result.bootstrap.ready()
    } else {
      result.key = result.local.key
      result.bootstrap = result.local.session({
        active: false,
        valueEncoding: messages.OplogMessage
      })
      await result.bootstrap.setUserData('autobase/local', result.local.key)
    }
  }

  if (key || keyPair) {
    await result.bootstrap.setUserData('referrer', result.key)
    await result.bootstrap.setUserData('autobase/local', result.local.key)
    await result.local.setUserData('referrer', result.key)
  }

  const [encryptionKeyBuffer, encryptionKeyEncryptedBuffer, pointer] = await Promise.all([
    result.local.getUserData('autobase/encryption'),
    result.local.getUserData('autobase/blind-encryption'),
    result.local.getUserData('autobase/boot')
  ])

  if (pointer) {
    result.boot = c.decode(messages.BootRecord, pointer)
  }

  if (encryptionKeyBuffer) {
    // if not encoded, replace
    if (blindEncryption) {
      const encrypted = await encryptionEncoding.encrypt(
        encryptionKeyBuffer,
        blindEncryption.encrypt
      )
      await result.local.setUserData('autobase/blind-encryption', encrypted)
      await result.local.setUserData('autobase/encryption', null)
    }

    result.encryptionKey = encryptionKeyBuffer
  }

  if (encryptionKeyEncryptedBuffer) {
    const { value, rotated } = await encryptionEncoding.decrypt(
      encryptionKeyEncryptedBuffer,
      blindEncryption.decrypt
    )

    if (rotated) {
      const encrypted = await encryptionEncoding.encrypt(value, blindEncryption.encrypt)
      await result.local.setUserData('autobase/blind-encryption', encrypted)
    }

    result.encryptionKey = value
  }

  if (!result.encryptionKey && (encryptionKey || encrypt)) {
    if (!encryptionKey) {
      encryptionKey = (await corestore.createKeyPair('autobase/encryption')).secretKey.subarray(
        0,
        32
      )
    }

    if (blindEncryption) {
      const encrypted = await encryptionEncoding.encrypt(encryptionKey, blindEncryption.encrypt)
      await result.local.setUserData('autobase/blind-encryption', encrypted)
    } else {
      await result.bootstrap.setUserData('autobase/encryption', encryptionKey) // legacy support
      await result.local.setUserData('autobase/encryption', encryptionKey)
    }
    result.encryptionKey = encryptionKey
  }

  return result
}