OverviewFilesCommitsIssuesDocsReleasesPeers

hyperident-shell / index.js

55 lines · javascript ref:
import fs from '#node:fs'
import os from '#node:os'
import path from '#node:path'
import process from '#node:process'
import b4a from 'b4a'
import HypercoreId from 'hypercore-id-encoding'

function homedir () {
  if (os.homedir) return os.homedir()
  return process.env.HOME || process.env.USERPROFILE || '.'
}

const DEFAULT_VAULT = () => path.join(homedir(), '.hyperident')

/**
 * Load the device keyPair straight from the hyperident vault.
 *
 * `device.key` is a 64-byte libsodium Ed25519 secret key (hex) and `device.pub`
 * the 32-byte public key (hex) — both stored plaintext regardless of any vault
 * passphrase. A libsodium 64-byte secret is `seed(32) || pub(32)`, and this is
 * itself a valid hyperdht keyPair, so it can be passed straight to
 * `server.listen(keyPair)` / `node.connect(pubkey, { keyPair })` — the shell's
 * address then equals the device pubkey. No keyfile is written to disk.
 *
 * Reads only via `#node:fs` (bare-fs on bare) — no pgh/hyperident runtime dep.
 */
export function loadDeviceKeyPair (vault = DEFAULT_VAULT()) {
  let secretHex, publicHex
  try {
    secretHex = fs.readFileSync(path.join(vault, 'device.key'), 'utf8').trim()
    publicHex = fs.readFileSync(path.join(vault, 'device.pub'), 'utf8').trim()
  } catch (e) {
    if (e.code === 'ENOENT') {
      throw new Error('no hyperident device identity at ' + vault + ' — run `pgh init` first')
    }
    throw e
  }

  const secretKey = b4a.from(secretHex, 'hex')
  const publicKey = b4a.from(publicHex, 'hex')
  if (secretKey.length !== 64 || publicKey.length !== 32) {
    throw new Error('unexpected device key sizes (secret=' + secretKey.length + ' public=' + publicKey.length + ')')
  }

  return {
    publicKey,
    secretKey,
    pub: HypercoreId.encode(publicKey), // z-base32 — the shell address
    publicKeyHex: publicHex
  }
}

export { serve } from './lib/server.js'
export { connect } from './lib/client.js'