nostr-dm-magiclink-utils
Version:
A comprehensive Nostr utility library for magic link authentication via direct messages, supporting both ESM and CommonJS. Features NIP-01/04 compliant message encryption, multi-relay support, internationalization (i18n) with RTL support, and TypeScript-f
122 lines • 3.65 kB
JavaScript
/**
* @module nips/nip01
* @description Implementation of NIP-01 functionality for direct messages
*/
import { getPublicKey, signEvent as cryptoSignEvent, verifySignature as cryptoVerifySignature } from 'nostr-crypto-utils';
import { NostrError, NostrErrorCode } from '../types/errors.js';
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@noble/hashes/utils';
/**
* Creates a new Nostr event with the specified parameters (NIP-01)
* @param params - Event parameters
* @returns Created event
*/
export function createEvent(params) {
const { kind, content, tags = [], created_at = Math.floor(Date.now() / 1000), pubkey = '' } = params;
return {
kind,
content,
tags,
created_at,
pubkey,
};
}
/**
* Serializes a Nostr event for signing/hashing (NIP-01)
* @param event - Event to serialize
* @returns Serialized event JSON string
*/
export function serializeEvent(event) {
return JSON.stringify([
0,
event.pubkey,
event.created_at,
event.kind,
event.tags,
event.content
]);
}
/**
* Calculates the hash of a Nostr event (NIP-01)
* @param event - Event to hash
* @returns Event hash in hex format
*/
export function calculateEventHash(event) {
const serialized = serializeEvent(event);
const hash = sha256(new TextEncoder().encode(serialized));
return bytesToHex(hash);
}
/**
* Creates and signs a Nostr event (NIP-01)
* @param params - Event parameters including private key
* @returns Signed event
*/
export async function signedEvent(params) {
try {
const { privateKey, ...eventParams } = params;
// Get public key if not provided
const pubkey = eventParams.pubkey || await getPublicKey(privateKey);
// Create the base event
const event = createEvent({ ...eventParams, pubkey });
// Calculate event hash/id
const id = calculateEventHash(event);
// Sign the event and get signature
const signature = await cryptoSignEvent(event, privateKey);
if (typeof signature !== 'string') {
throw new Error('Invalid signature format');
}
// Return the signed event
return {
...event,
id,
sig: signature
};
}
catch (error) {
throw new NostrError('Failed to create signed event', NostrErrorCode.EVENT_CREATION_FAILED);
}
}
/**
* Verifies a Nostr event's signature (NIP-01)
* @param event - Event to verify
* @returns True if signature is valid
*/
export async function verifyEvent(event) {
try {
return await cryptoVerifySignature(event);
}
catch (error) {
throw new NostrError('Failed to verify event', NostrErrorCode.EVENT_VERIFICATION_FAILED);
}
}
/**
* Validates a Nostr event structure (NIP-01)
* @param event - Event to validate
* @returns True if event structure is valid
*/
export function validateEvent(event) {
try {
if (!event.pubkey || !event.created_at || event.kind === undefined || !event.content) {
return false;
}
// Check timestamp is not in the future
const now = Math.floor(Date.now() / 1000);
if (event.created_at > now) {
return false;
}
// Validate tags structure
if (!Array.isArray(event.tags)) {
return false;
}
for (const tag of event.tags) {
if (!Array.isArray(tag)) {
return false;
}
}
return true;
}
catch {
return false;
}
}
//# sourceMappingURL=nip01.js.map