mirror your GitHub repos to tangled.org automatically
1

Configure Feed

Select the types of activity you want to include in your feed.

1import crypto from 'node:crypto' 2 3/** 4 * Generate an ed25519 SSH keypair. Returns the OpenSSH-formatted public key 5 * (suitable for `sh.tangled.publicKey` records / GitHub deploy keys / authorized_keys) 6 * and the PKCS#8-PEM-encoded private key (suitable for storage). 7 * 8 * We store PKCS#8 because Node loads it natively via `crypto.createPrivateKey`. 9 * Conversion to OpenSSH private key format (what `git`/`ssh-agent` consumes) is 10 * deferred until commit 12, where it lives next to the SSH push code. 11 */ 12export interface GeneratedKeypair { 13 publicKeyOpenSsh: string 14 privateKeyPem: string 15} 16 17export function generateKeypair(comment: string): GeneratedKeypair { 18 const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519', { 19 publicKeyEncoding: { type: 'spki', format: 'der' }, 20 privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, 21 }) 22 23 // SPKI-DER for ed25519 is a fixed 44-byte ASN.1 wrapper; the last 32 bytes 24 // are the raw public key. (See RFC 8410 §4.) Skip the wrapper. 25 const rawPublic = (publicKey as Buffer).subarray(-32) 26 27 return { 28 publicKeyOpenSsh: encodeOpenSshEd25519(rawPublic, comment), 29 privateKeyPem: privateKey as string, 30 } 31} 32 33/** 34 * Encode a 32-byte ed25519 public key in OpenSSH `authorized_keys` format: 35 * ssh-ed25519 <base64(string("ssh-ed25519") + string(rawKey))> <comment> 36 * 37 * The base64 payload uses SSH's length-prefixed string format (uint32 big-endian 38 * length + bytes), per RFC 4253 §6.6 and the ed25519 draft. 39 */ 40function encodeOpenSshEd25519(rawPublicKey: Buffer, comment: string): string { 41 if (rawPublicKey.length !== 32) { 42 throw new Error(`expected 32 raw bytes for ed25519 public key, got ${rawPublicKey.length}`) 43 } 44 45 const algo = Buffer.from('ssh-ed25519', 'utf8') 46 const payload = Buffer.concat([ 47 sshString(algo), 48 sshString(rawPublicKey), 49 ]) 50 return `ssh-ed25519 ${payload.toString('base64')} ${comment}` 51} 52 53function sshString(buf: Buffer): Buffer { 54 const len = Buffer.alloc(4) 55 len.writeUInt32BE(buf.length, 0) 56 return Buffer.concat([len, buf]) 57}