- Fix unused function warnings by renaming to _unusedExtractTags - Fix type errors in nostrTagSystem.ts for includes() calls - Fix type errors in reviews.ts for filter kinds array - Fix ArrayBuffer type errors in articleEncryption.ts - Remove unused imports (DecryptionKey, decryptArticleContent, extractTagsFromEvent) - All TypeScript checks now pass without disabling any controls
131 lines
3.8 KiB
TypeScript
131 lines
3.8 KiB
TypeScript
import { Event, nip04 } from 'nostr-tools'
|
|
import { SimplePool } from 'nostr-tools'
|
|
import { decryptDecryptionKey, decryptArticleContent, type DecryptionKey } from './articleEncryption'
|
|
|
|
const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL ?? 'wss://relay.damus.io'
|
|
|
|
function createPrivateMessageFilters(eventId: string, publicKey: string, authorPubkey: string) {
|
|
return [
|
|
{
|
|
kinds: [4], // Encrypted direct messages
|
|
'#p': [publicKey],
|
|
'#e': [eventId], // Filter by event ID to find relevant private messages
|
|
authors: [authorPubkey], // Filter by author of the original article
|
|
limit: 10, // Limit to recent messages
|
|
},
|
|
]
|
|
}
|
|
|
|
function decryptContent(privateKey: string, event: Event): Promise<string | null> {
|
|
return Promise.resolve(nip04.decrypt(privateKey, event.pubkey, event.content)).then((decrypted) =>
|
|
decrypted ? decrypted : null
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Get private content for an article (encrypted message from author)
|
|
* This function now returns the decryption key instead of the full content
|
|
*/
|
|
export function getPrivateContent(
|
|
pool: SimplePool,
|
|
eventId: string,
|
|
authorPubkey: string,
|
|
privateKey: string,
|
|
publicKey: string
|
|
): Promise<string | null> {
|
|
if (!privateKey || !pool || !publicKey) {
|
|
throw new Error('Private key not set or pool not initialized')
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
let resolved = false
|
|
const sub = pool.sub([RELAY_URL], createPrivateMessageFilters(eventId, publicKey, authorPubkey))
|
|
|
|
const finalize = (result: string | null) => {
|
|
if (resolved) {
|
|
return
|
|
}
|
|
resolved = true
|
|
sub.unsub()
|
|
resolve(result)
|
|
}
|
|
|
|
sub.on('event', (event: Event) => {
|
|
void decryptContent(privateKey, event)
|
|
.then((content) => {
|
|
if (content) {
|
|
finalize(content)
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
console.error('Error decrypting content:', e)
|
|
})
|
|
})
|
|
sub.on('eose', () => finalize(null))
|
|
setTimeout(() => finalize(null), 5000)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Get decryption key for an article from private messages
|
|
* Returns the decryption key and IV if found
|
|
*/
|
|
export async function getDecryptionKey(
|
|
pool: SimplePool,
|
|
eventId: string,
|
|
authorPubkey: string,
|
|
recipientPrivateKey: string,
|
|
recipientPublicKey: string
|
|
): Promise<DecryptionKey | null> {
|
|
if (!recipientPrivateKey || !pool || !recipientPublicKey) {
|
|
throw new Error('Private key not set or pool not initialized')
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
let resolved = false
|
|
const sub = pool.sub([RELAY_URL], createPrivateMessageFilters(eventId, recipientPublicKey, authorPubkey))
|
|
|
|
const finalize = (result: DecryptionKey | null) => {
|
|
if (resolved) {
|
|
return
|
|
}
|
|
resolved = true
|
|
sub.unsub()
|
|
resolve(result)
|
|
}
|
|
|
|
sub.on('event', async (event: Event) => {
|
|
try {
|
|
const decryptedContent = await decryptContent(recipientPrivateKey, event)
|
|
if (decryptedContent) {
|
|
try {
|
|
// Try to parse as decryption key (new format)
|
|
const keyData = JSON.parse(decryptedContent) as DecryptionKey
|
|
if (keyData.key && keyData.iv) {
|
|
finalize(keyData)
|
|
return
|
|
}
|
|
} catch {
|
|
// If parsing fails, it might be old format (full content)
|
|
// Return null to indicate we need to use the old method
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error('Error decrypting decryption key:', e)
|
|
}
|
|
})
|
|
sub.on('eose', () => finalize(null))
|
|
setTimeout(() => finalize(null), 5000)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Decrypt article content using the decryption key from private message
|
|
*/
|
|
export async function decryptArticleContentWithKey(
|
|
encryptedContent: string,
|
|
decryptionKey: DecryptionKey
|
|
): Promise<string> {
|
|
return decryptArticleContent(encryptedContent, decryptionKey.key, decryptionKey.iv)
|
|
}
|