forked from snxraven/peardock
Replace ad-hoc console output with a structured logger (pretty/JSON, levels, redaction, optional file rotation), a clean startup banner with Docker/feature probes, graceful shutdown signals, and slow-RPC warnings.
68 lines
2.3 KiB
JavaScript
68 lines
2.3 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]
|
|
* @returns {{ seed: Uint8Array, keyPair: { publicKey: Uint8Array, secretKey: Uint8Array }, publicKeyHex: string, seedHex: string }}
|
|
*/
|
|
export function loadOrCreateKeyPair(envPath = '.env') {
|
|
let seedHex = process.env.SERVER_SEED || process.env.SERVER_KEY
|
|
|
|
// SERVER_KEY historically was a 32-byte topic seed; reuse as DHT seed if present
|
|
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 / SERVER_KEY 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')
|
|
|
|
// Keep PUBLIC_KEY in env for operator convenience
|
|
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=') && !process.env.SERVER_SEED) {
|
|
// migrate old SERVER_KEY-only files
|
|
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 })
|
|
}
|
|
}
|
|
|
|
return { seed, keyPair, publicKeyHex, seedHex }
|
|
}
|