Skip to content

Commit 75d6ce7

Browse files
vveerrggclaude
andcommitted
feat: upgrade to nostr-crypto-utils v0.5.1, use finalizeEvent and getPublicKeySync
Switch crypto utils wrapper to use finalizeEvent() (one-step event creation + signing) and getPublicKeySync() (sync pubkey derivation). Simplifies generateChallenge() from a 3-step manual pattern to a single call. Also fixes loadConfig() to derive pubkey from the actual SERVER_PRIVATE_KEY instead of a random keypair. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ac66a50 commit 75d6ce7

5 files changed

Lines changed: 55 additions & 36 deletions

File tree

package-lock.json

Lines changed: 27 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"express-rate-limit": "^7.5.1",
8383
"helmet": "^8.1.0",
8484
"jsonwebtoken": "^9.0.3",
85-
"nostr-crypto-utils": "^0.4.10",
85+
"nostr-crypto-utils": "^0.5.1",
8686
"tslib": "^2.8.1",
8787
"winston": "^3.19.0"
8888
},

src/config/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { createLogger } from '../utils/logger.js';
8-
import { generateKeyPair } from '../utils/crypto.utils.js';
8+
import { generateKeyPair, getPublicKey } from '../utils/crypto.utils.js';
99
import { createClient } from '@supabase/supabase-js';
1010
import dotenv from 'dotenv';
1111
import { NostrConfig } from '../types/index.js';
@@ -132,9 +132,8 @@ export async function loadConfig(envPath?: string): Promise<NostrConfig> {
132132
// SECURITY: Prefer loading server keys from environment variables (SERVER_PRIVATE_KEY).
133133
// This avoids storing private keys as plaintext in Supabase.
134134
if (process.env.SERVER_PRIVATE_KEY) {
135-
const keyPair = await generateKeyPair();
136135
loadedConfig.privateKey = process.env.SERVER_PRIVATE_KEY;
137-
loadedConfig.publicKey = keyPair.publicKey.toString();
136+
loadedConfig.publicKey = getPublicKey(process.env.SERVER_PRIVATE_KEY);
138137
logger.info('Loaded server keys from environment (recommended for production)');
139138
return loadedConfig;
140139
}

src/types/nostr-crypto-utils.d.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
declare module 'nostr-crypto-utils' {
2-
export function generateKeyPair(): { privateKey: string; publicKey: string };
3-
export function getPublicKey(privateKey: string): Promise<string>;
2+
export function generateKeyPair(): Promise<{ privateKey: string; publicKey: string }>;
3+
export function getPublicKey(privateKey: string): Promise<{ hex: string; bytes: Uint8Array }>;
4+
export function getPublicKeySync(privateKey: string): string;
45
export function calculateEventId(event: any): string;
6+
export function createEvent(event: Partial<any>): any;
57
export function signEvent(event: any, privateKey: string): Promise<any>;
8+
export function finalizeEvent(event: Partial<any>, privateKey: string): Promise<any>;
69
export function verifySignature(event: any): Promise<boolean>;
710
}

src/utils/crypto.utils.ts

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
* @module crypto-utils
55
*/
66

7-
import {
7+
import {
88
generateKeyPair as genKeyPair,
9-
getPublicKey as getNostrPublicKey,
9+
getPublicKeySync,
1010
calculateEventId as getEventHash,
11-
signEvent as signNostrEvent,
11+
finalizeEvent,
1212
verifySignature as verifyNostrSignature
1313
} from 'nostr-crypto-utils';
1414
import { NostrEvent } from '../types.js';
@@ -22,13 +22,12 @@ export function generateKeyPair() {
2222
}
2323

2424
/**
25-
* Derives a public key from a private key
25+
* Derives a public key from a private key (synchronous)
2626
* @param {string} privateKey - The private key in hex format
27-
* @returns {Promise<string>} The derived public key in hex format
27+
* @returns {string} The derived public key in hex format
2828
*/
29-
export async function getPublicKey(privateKey: string): Promise<string> {
30-
const publicKeyDetails = await getNostrPublicKey(privateKey);
31-
return publicKeyDetails.toString();
29+
export function getPublicKey(privateKey: string): string {
30+
return getPublicKeySync(privateKey);
3231
}
3332

3433
/**
@@ -50,34 +49,29 @@ export function generateEventHash(event: Partial<NostrEvent>): string {
5049
}
5150

5251
/**
53-
* Signs a Nostr event with a private key
52+
* Signs a Nostr event with a private key using finalizeEvent
5453
* @param {NostrEvent} event - The event to sign
5554
* @param {string} privateKey - The private key to sign with
56-
* @returns {Promise<NostrEvent>} The signed event
55+
* @returns {Promise<NostrEvent>} The signed event with id, pubkey, and sig
5756
*/
5857
export async function signEvent(event: NostrEvent, privateKey: string): Promise<NostrEvent> {
59-
return signNostrEvent(event, privateKey);
58+
const signed = await finalizeEvent(event, privateKey);
59+
return signed as unknown as NostrEvent;
6060
}
6161

6262
/**
6363
* Generates a challenge event for authentication
64-
* @param {string} pubkey - The public key to generate the challenge for
65-
* @returns {Promise<NostrEvent>} The generated challenge event
64+
* @param {string} privateKey - The server's private key to sign the challenge with
65+
* @param {string} challengePubkey - The public key to generate the challenge for
66+
* @returns {Promise<NostrEvent>} The generated and signed challenge event
6667
*/
67-
export async function generateChallenge(pubkey: string): Promise<NostrEvent> {
68-
const now = Math.floor(Date.now() / 1000);
69-
const event: NostrEvent = {
68+
export async function generateChallenge(privateKey: string, challengePubkey?: string): Promise<NostrEvent> {
69+
const pubkey = challengePubkey ?? getPublicKeySync(privateKey);
70+
const signed = await finalizeEvent({
7071
kind: 22242,
71-
created_at: now,
7272
tags: [['challenge', pubkey]],
73-
content: 'Authentication request',
74-
pubkey: pubkey,
75-
id: '',
76-
sig: ''
77-
};
73+
content: 'Authentication request'
74+
}, privateKey);
7875

79-
event.id = getEventHash(event);
80-
event.sig = await signNostrEvent(event, pubkey);
81-
82-
return event;
76+
return signed as unknown as NostrEvent;
8377
}

0 commit comments

Comments
 (0)