OverviewFilesCommitsIssuesDocsReleasesPeers

pgh / lib / commands / ssh-key.js

71 lines · javascript ref:
/**
 * pgh ssh-key list|add|remove — manage authorized SSH keys for git push over
 * SSH (classic-git-auth Channel A: operator enrollment over the daemon UDS).
 *
 * Thin wrapper over the daemon handlers add-ssh-key / list-ssh-keys /
 * remove-ssh-key. A key is registered as an `ssh-key` identity and linked to a
 * User; that user's write permission gates the push. Reads stay open. Enrolling
 * (re)generates the daemon's ~/.ssh/authorized_keys managed block, so the key
 * can push to THIS daemon over SSH.
 */

import fs from '#node:fs'

export const usage = `pgh ssh-key — manage authorized SSH keys (git push over SSH)

  pgh ssh-key [list]                          List enrolled SSH keys
  pgh ssh-key list --user <id>                List a specific user's keys
  pgh ssh-key add "<ssh-pubkey>" [--user <id>]   Enroll a public key (defaults to repo owner)
  pgh ssh-key add --file <path.pub> [--user <id>]
  pgh ssh-key remove SHA256:<fp>              Revoke an enrolled key

Notes:
  - Enroll on the daemon that should ACCEPT the push (default pear-git-v3;
    use --app <name> to target another local app).
  - The fingerprint is the OpenSSH SHA-256 fp (matches \`ssh-keygen -lf\`).
  - Revoke denies the next push live (no authorized_keys edit needed).`

function flagValue (args, name) {
  const i = args.indexOf('--' + name)
  if (i !== -1 && i + 1 < args.length) return args[i + 1]
  const pfx = '--' + name + '='
  for (const a of args) if (a.startsWith(pfx)) return a.slice(pfx.length)
  return null
}

export async function run (client, args) {
  const sub = (args[0] && !args[0].startsWith('-')) ? args[0] : 'list'
  const userId = flagValue(args, 'user')

  if (sub === 'list') {
    const out = await client.call('list-ssh-keys', userId ? { userId } : {})
    return out
  }

  if (sub === 'add') {
    const file = flagValue(args, 'file')
    let publicKey = null
    if (file) {
      publicKey = fs.readFileSync(file, 'utf8').trim()
    } else {
      // First non-flag arg after `add` is the inline public key.
      const positional = args.slice(1).find(a => !a.startsWith('-'))
      publicKey = positional ? positional.trim() : null
    }
    if (!publicKey) throw new Error('usage: pgh ssh-key add "<ssh-pubkey>" | --file <path.pub> [--user <id>]')
    const params = { publicKey }
    if (userId) params.userId = userId
    return client.call('add-ssh-key', params)
  }

  if (sub === 'remove' || sub === 'rm') {
    const fp = args.slice(1).find(a => !a.startsWith('-'))
    if (!fp || fp.indexOf('SHA256:') !== 0) {
      throw new Error('usage: pgh ssh-key remove SHA256:<fingerprint>')
    }
    return client.call('remove-ssh-key', { fingerprint: fp })
  }

  throw new Error('unknown ssh-key subcommand: ' + sub + '\n' + usage)
}