Compare commits
2 commits
3468972733
...
4a0a3e7cd4
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a0a3e7cd4 | |||
| 2cf3e55bf4 |
1 changed files with 38 additions and 0 deletions
|
|
@ -2,6 +2,8 @@ import NDK, { NDKEvent, NDKPrivateKeySigner, NDKRpcRequest, type NostrEvent } fr
|
||||||
import AdminInterface from "../index.js";
|
import AdminInterface from "../index.js";
|
||||||
import { NIP46_ADMIN_RESPONSE_KIND } from "../kinds.js";
|
import { NIP46_ADMIN_RESPONSE_KIND } from "../kinds.js";
|
||||||
import { saveEncrypted } from "../../../commands/add.js";
|
import { saveEncrypted } from "../../../commands/add.js";
|
||||||
|
import { getCurrentConfig } from "../../../config/index.js";
|
||||||
|
import { decryptNsec } from "../../../config/keys.js";
|
||||||
import { setupSkeletonProfile } from "../../lib/profile.js";
|
import { setupSkeletonProfile } from "../../lib/profile.js";
|
||||||
|
|
||||||
export default async function createNewKey(admin: AdminInterface, req: NDKRpcRequest) {
|
export default async function createNewKey(admin: AdminInterface, req: NDKRpcRequest) {
|
||||||
|
|
@ -10,6 +12,42 @@ export default async function createNewKey(admin: AdminInterface, req: NDKRpcReq
|
||||||
if (!keyName || !passphrase) throw new Error("Invalid params");
|
if (!keyName || !passphrase) throw new Error("Invalid params");
|
||||||
if (!admin.loadNsec) throw new Error("No unlockKey method");
|
if (!admin.loadNsec) throw new Error("No unlockKey method");
|
||||||
|
|
||||||
|
// Idempotency guard. Callers re-pair a machine through the same keyName
|
||||||
|
// (e.g. spirekeeper's `spire-<id>`) and rely on create_new_key being
|
||||||
|
// idempotent — "returns the existing key if the name is taken". Without
|
||||||
|
// this guard the command unconditionally generated a FRESH key and
|
||||||
|
// `saveEncrypted` overwrote the existing encrypted blob on disk, silently
|
||||||
|
// destroying the in-use signing identity (unrecoverable — the old nsec then
|
||||||
|
// survives only in the running process until the next restart). NEVER
|
||||||
|
// generate-and-overwrite an existing name: recover and return it instead.
|
||||||
|
const currentConfig = await getCurrentConfig(admin.configFile);
|
||||||
|
const existing = currentConfig.keys?.[keyName];
|
||||||
|
if (existing) {
|
||||||
|
if (_nsec) {
|
||||||
|
throw new Error(
|
||||||
|
`key '${keyName}' already exists; refusing to overwrite it with an ` +
|
||||||
|
`imported nsec — delete it explicitly first if replacement is intended`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!existing.iv || !existing.data) {
|
||||||
|
throw new Error(
|
||||||
|
`key '${keyName}' already exists in an unrecognized form; refusing to overwrite`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let existingNsec: string;
|
||||||
|
try {
|
||||||
|
existingNsec = decryptNsec(existing.iv, existing.data, passphrase);
|
||||||
|
} catch (e: any) {
|
||||||
|
throw new Error(
|
||||||
|
`key '${keyName}' already exists but the supplied passphrase did not ` +
|
||||||
|
`decrypt it; refusing to overwrite (${e.message})`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const existingUser = await new NDKPrivateKeySigner(existingNsec).user();
|
||||||
|
const result = JSON.stringify({ npub: existingUser.npub });
|
||||||
|
return admin.rpc.sendResponse(req.id, req.pubkey, result, NIP46_ADMIN_RESPONSE_KIND);
|
||||||
|
}
|
||||||
|
|
||||||
let key;
|
let key;
|
||||||
|
|
||||||
if (_nsec) {
|
if (_nsec) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue