askexperts
Version:
AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol
133 lines • 5 kB
JavaScript
/**
* Encryption utilities for NIP-173
* Supports both "none" and "nip44" encryption types
*/
import { nip44 } from 'nostr-tools';
import { debugError } from "../common/debug.js";
// Encryption types
export const ENCRYPTION_NONE = "none";
export const ENCRYPTION_NIP44 = "nip44";
// 64Kb - 1 byte
export const MAX_PAYLOAD_SIZE_NIP44_BIN = 64 * 1024 - 1;
// Payload is base64 encoded first
export const MAX_PAYLOAD_SIZE_NIP44 = Math.floor(MAX_PAYLOAD_SIZE_NIP44_BIN / 4 * 3);
/**
* Error thrown when encryption or decryption fails
*/
export class EncryptionError extends Error {
constructor(message) {
super(message);
this.name = "EncryptionError";
}
}
/**
* Default implementation of the Encryption interface
* Provides built-in support for 'none' and 'nip44' encryption methods
*/
export class DefaultEncryption {
async maxChunkSize(type) {
if (type === ENCRYPTION_NIP44) {
// NIP-44 max payload size limit
return Promise.resolve(MAX_PAYLOAD_SIZE_NIP44);
}
}
/**
* Encrypts data using the specified encryption method
*
* @param data - The data to encrypt as string or Uint8Array
* @param type - The encryption method
* @param senderPrivkey - Sender's private key (for nip44)
* @param recipientPubkey - Recipient's public key (for nip44)
* @returns Encrypted data as string
*/
async encrypt(data, type, senderPrivkey, recipientPubkey) {
// Convert Uint8Array to string if needed
const stringData = typeof data === "string"
? data
: Buffer.from(data).toString("base64");
if (type === ENCRYPTION_NONE) {
// No encryption, just return the data as string
return stringData;
}
else if (type === ENCRYPTION_NIP44) {
// Validate required parameters for NIP-44
if (!senderPrivkey || !recipientPubkey) {
throw new EncryptionError("NIP-44 encryption requires sender private key and recipient public key");
}
try {
// Get conversation key and encrypt
const conversationKey = nip44.getConversationKey(senderPrivkey, recipientPubkey);
return nip44.encrypt(stringData, conversationKey);
}
catch (error) {
debugError("NIP-44 encryption failed:", error);
throw new EncryptionError(`NIP-44 encryption failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
else {
throw new EncryptionError(`Unsupported encryption method: ${type}`);
}
}
/**
* Decrypts data using the specified encryption method
*
* @param data - The encrypted data as string
* @param type - The encryption method
* @param binary - Whether to return binary data instead of string
* @param recipientPrivkey - Recipient's private key (for nip44)
* @param senderPubkey - Sender's public key (for nip44)
* @returns Decrypted data as string or Uint8Array (if binary)
*/
async decrypt(data, type, binary, recipientPrivkey, senderPubkey) {
let decryptedString;
if (type === ENCRYPTION_NONE) {
// No encryption, just use the data as is
decryptedString = data;
}
else if (type === ENCRYPTION_NIP44) {
// Validate required parameters for NIP-44
if (!recipientPrivkey || !senderPubkey) {
throw new EncryptionError("NIP-44 decryption requires recipient private key and sender public key");
}
try {
// Get conversation key and decrypt
const conversationKey = nip44.getConversationKey(recipientPrivkey, senderPubkey);
decryptedString = nip44.decrypt(data, conversationKey);
}
catch (error) {
debugError("NIP-44 decryption failed:", error);
throw new EncryptionError(`NIP-44 decryption failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
else {
throw new EncryptionError(`Unsupported encryption method: ${type}`);
}
// Return binary data or string based on the binary flag
if (binary) {
return new Uint8Array(Buffer.from(decryptedString, "base64"));
}
else {
return decryptedString;
}
}
/**
* Returns a list of supported encryption methods
*
* @returns Array of supported encryption method names
*/
list() {
return [ENCRYPTION_NONE, ENCRYPTION_NIP44];
}
}
// Singleton instance
let encryption;
/**
* Returns the default encryption instance
* Creates a new instance if one doesn't exist
*/
export function getEncryption() {
if (!encryption)
encryption = new DefaultEncryption();
return encryption;
}
//# sourceMappingURL=encryption.js.map