Files
peardata/server/core/keys.js
T
Raven Scott 015d92a257
Release rolling / release (push) Has been cancelled
CI / test (push) Has been cancelled
first commit
2026-07-18 16:17:38 -04:00

65 lines
1.9 KiB
JavaScript

/**
* Persistent HyperDHT keypair management.
* SERVER_SEED (32-byte hex) is the secret seed.
* Clients connect using the derived public key.
*/
import fs from 'fs'
import path from 'path'
import DHT from 'hyperdht'
import b4a from 'b4a'
import crypto from 'hypercore-crypto'
import dotenv from 'dotenv'
import logger from '../utils/logger.js'
dotenv.config()
const log = logger.child('keys')
/**
* @param {string} [envPath]
*/
export function loadOrCreateKeyPair(envPath = '.env') {
let seedHex = process.env.SERVER_SEED || process.env.SERVER_KEY
if (!seedHex) {
const seed = crypto.randomBytes(32)
seedHex = b4a.toString(seed, 'hex')
const publicKeyHex = b4a.toString(DHT.keyPair(seed).publicKey, 'hex')
const line = `\nSERVER_SEED=${seedHex}\nSERVER_PUBLIC_KEY=${publicKeyHex}\n`
fs.appendFileSync(envPath, line, { flag: 'a' })
log.info('Generated new SERVER_SEED and SERVER_PUBLIC_KEY', {
path: path.resolve(envPath),
})
}
if (!/^[0-9a-fA-F]{64}$/.test(seedHex)) {
throw new Error('SERVER_SEED must be 64 hex characters (32 bytes)')
}
const seed = b4a.from(seedHex, 'hex')
const keyPair = DHT.keyPair(seed)
const publicKeyHex = b4a.toString(keyPair.publicKey, 'hex')
if (process.env.SERVER_PUBLIC_KEY !== publicKeyHex) {
try {
let env = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf8') : ''
if (env.includes('SERVER_PUBLIC_KEY=')) {
env = env.replace(/SERVER_PUBLIC_KEY=.*/g, `SERVER_PUBLIC_KEY=${publicKeyHex}`)
} else {
env += `\nSERVER_PUBLIC_KEY=${publicKeyHex}\n`
}
if (!env.includes('SERVER_SEED=')) {
env += `SERVER_SEED=${seedHex}\n`
}
fs.writeFileSync(envPath, env)
} catch (err) {
log.warn('Could not update .env with SERVER_PUBLIC_KEY', { error: err.message })
}
}
process.env.SERVER_SEED = seedHex
process.env.SERVER_PUBLIC_KEY = publicKeyHex
return { seed, keyPair, publicKeyHex, seedHex }
}