89 lines
2.1 KiB
JavaScript
89 lines
2.1 KiB
JavaScript
/**
|
|
* Persistent client DHT identity for stable peerId across reconnects.
|
|
* Stored at ~/.config/peardata/identity.json (mode 0600).
|
|
*
|
|
* Uses fs/path/os/crypto via package.json import maps → bare-* under Bare/Pear.
|
|
*/
|
|
import fs from 'fs'
|
|
import path from 'path'
|
|
import os from 'os'
|
|
import crypto from 'crypto'
|
|
import DHT from 'hyperdht'
|
|
import b4a from 'b4a'
|
|
|
|
const IDENTITY_VERSION = 1
|
|
|
|
function envGet(name) {
|
|
try {
|
|
return typeof process !== 'undefined' ? process.env?.[name] : undefined
|
|
} catch {
|
|
return undefined
|
|
}
|
|
}
|
|
|
|
export function getIdentityPath() {
|
|
const home =
|
|
envGet('PEARDATA_HOME') ||
|
|
envGet('HOME') ||
|
|
envGet('USERPROFILE') ||
|
|
(typeof os.homedir === 'function' ? os.homedir() : '') ||
|
|
''
|
|
return path.join(home, '.config', 'peardata', 'identity.json')
|
|
}
|
|
|
|
export function loadOrCreateClientIdentity() {
|
|
const filePath = getIdentityPath()
|
|
let seedHex = null
|
|
|
|
try {
|
|
if (fs.existsSync(filePath)) {
|
|
const raw = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
if (raw?.seedHex && /^[0-9a-fA-F]{64}$/.test(raw.seedHex)) {
|
|
seedHex = String(raw.seedHex).toLowerCase()
|
|
}
|
|
}
|
|
} catch {
|
|
// regenerate
|
|
}
|
|
|
|
if (!seedHex) {
|
|
seedHex = b4a.toString(crypto.randomBytes(32), 'hex')
|
|
try {
|
|
const dir = path.dirname(filePath)
|
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
|
|
fs.writeFileSync(
|
|
filePath,
|
|
JSON.stringify(
|
|
{
|
|
version: IDENTITY_VERSION,
|
|
seedHex,
|
|
createdAt: new Date().toISOString(),
|
|
},
|
|
null,
|
|
2
|
|
),
|
|
{ mode: 0o600 }
|
|
)
|
|
try {
|
|
fs.chmodSync(filePath, 0o600)
|
|
} catch {
|
|
// ignore
|
|
}
|
|
} catch {
|
|
// In-memory only if FS unavailable
|
|
}
|
|
}
|
|
|
|
const seed = b4a.from(seedHex, 'hex')
|
|
const keyPair = DHT.keyPair(seed)
|
|
const publicKeyHex = b4a.toString(keyPair.publicKey, 'hex')
|
|
return { seed, keyPair, publicKeyHex, seedHex }
|
|
}
|
|
|
|
let cached = null
|
|
|
|
export function getClientIdentity() {
|
|
if (!cached) cached = loadOrCreateClientIdentity()
|
|
return cached
|
|
}
|