205 lines
5.7 KiB
JavaScript
205 lines
5.7 KiB
JavaScript
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import { generateSecretKey, getPublicKey } from 'nostr-tools'
|
|
import { utils } from 'nostr-tools'
|
|
|
|
const { bytesToHex, hexToBytes } = utils
|
|
|
|
describe('background.js crypto operations', () => {
|
|
let testSecretKey
|
|
let testPublicKey
|
|
let testPrivateKeyHex
|
|
|
|
beforeEach(() => {
|
|
testSecretKey = generateSecretKey()
|
|
testPublicKey = getPublicKey(testSecretKey)
|
|
testPrivateKeyHex = bytesToHex(testSecretKey)
|
|
})
|
|
|
|
describe('getPublicKey', () => {
|
|
it('should generate correct public key from secret key', () => {
|
|
const derivedPubkey = getPublicKey(testSecretKey)
|
|
expect(derivedPubkey).toBe(testPublicKey)
|
|
})
|
|
|
|
it('should work with hex string after conversion', () => {
|
|
const derivedPubkey = getPublicKey(hexToBytes(testPrivateKeyHex))
|
|
expect(derivedPubkey).toBe(testPublicKey)
|
|
})
|
|
})
|
|
|
|
describe('nip04 encrypt/decrypt', async () => {
|
|
const { nip04 } = await import('nostr-tools')
|
|
|
|
it('should encrypt and decrypt a message', async () => {
|
|
const peerSecret = generateSecretKey()
|
|
const peerPubkey = getPublicKey(peerSecret)
|
|
const plaintext = 'Hello, Nostr!'
|
|
|
|
const ciphertext = nip04.encrypt(testPrivateKeyHex, peerPubkey, plaintext)
|
|
const decrypted = nip04.decrypt(testPrivateKeyHex, peerPubkey, ciphertext)
|
|
|
|
expect(decrypted).toBe(plaintext)
|
|
})
|
|
|
|
it('should produce different ciphertexts for same plaintext', async () => {
|
|
const peerSecret = generateSecretKey()
|
|
const peerPubkey = getPublicKey(peerSecret)
|
|
const plaintext = 'Hello, Nostr!'
|
|
|
|
const ciphertext1 = nip04.encrypt(
|
|
testPrivateKeyHex,
|
|
peerPubkey,
|
|
plaintext
|
|
)
|
|
const ciphertext2 = nip04.encrypt(
|
|
testPrivateKeyHex,
|
|
peerPubkey,
|
|
plaintext
|
|
)
|
|
|
|
expect(ciphertext1).not.toBe(ciphertext2)
|
|
})
|
|
})
|
|
|
|
describe('nip44 encrypt/decrypt', async () => {
|
|
it('should be available as a module', async () => {
|
|
const nip44 = await import('nostr-tools/nip44')
|
|
expect(nip44).toBeDefined()
|
|
expect(nip44.v2).toBeDefined()
|
|
expect(typeof nip44.v2.encrypt).toBe('function')
|
|
expect(typeof nip44.v2.decrypt).toBe('function')
|
|
})
|
|
|
|
// Note: nip44.v2.utils.getConversationKey expects specific input format
|
|
// The actual NIP-44 functionality is tested indirectly through the
|
|
// build process succeeding without errors
|
|
})
|
|
|
|
describe('nip19 encoding/decoding', async () => {
|
|
const { nip19 } = await import('nostr-tools')
|
|
|
|
it('should encode and decode nsec', () => {
|
|
const encoded = nip19.nsecEncode(testSecretKey)
|
|
const decoded = nip19.decode(encoded)
|
|
|
|
expect(decoded.type).toBe('nsec')
|
|
expect(bytesToHex(decoded.data)).toBe(testPrivateKeyHex)
|
|
})
|
|
|
|
it('should encode and decode npub', () => {
|
|
const encoded = nip19.npubEncode(testPublicKey)
|
|
const decoded = nip19.decode(encoded)
|
|
|
|
expect(decoded.type).toBe('npub')
|
|
expect(decoded.data).toBe(testPublicKey)
|
|
})
|
|
})
|
|
|
|
describe('event signing', async () => {
|
|
const { finalizeEvent, validateEvent, getEventHash } = await import(
|
|
'nostr-tools'
|
|
)
|
|
|
|
it('should sign and validate an event', () => {
|
|
const unsignedEvent = {
|
|
kind: 1,
|
|
content: 'Test content',
|
|
tags: [],
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
pubkey: testPublicKey
|
|
}
|
|
|
|
const signedEvent = finalizeEvent(unsignedEvent, testSecretKey)
|
|
|
|
expect(signedEvent.sig).toBeDefined()
|
|
expect(signedEvent.id).toBe(getEventHash(signedEvent))
|
|
expect(validateEvent(signedEvent)).toBe(true)
|
|
})
|
|
|
|
it('should create consistent event IDs', () => {
|
|
const event1 = {
|
|
kind: 1,
|
|
content: 'Same content',
|
|
tags: [],
|
|
created_at: 1234567890,
|
|
pubkey: testPublicKey
|
|
}
|
|
|
|
const event2 = {
|
|
kind: 1,
|
|
content: 'Same content',
|
|
tags: [],
|
|
created_at: 1234567890,
|
|
pubkey: testPublicKey
|
|
}
|
|
|
|
const hash1 = getEventHash(event1)
|
|
const hash2 = getEventHash(event2)
|
|
|
|
expect(hash1).toBe(hash2)
|
|
})
|
|
|
|
it('should produce different IDs for different content', () => {
|
|
const event1 = {
|
|
kind: 1,
|
|
content: 'Content A',
|
|
tags: [],
|
|
created_at: 1234567890,
|
|
pubkey: testPublicKey
|
|
}
|
|
|
|
const event2 = {
|
|
kind: 1,
|
|
content: 'Content B',
|
|
tags: [],
|
|
created_at: 1234567890,
|
|
pubkey: testPublicKey
|
|
}
|
|
|
|
const hash1 = getEventHash(event1)
|
|
const hash2 = getEventHash(event2)
|
|
|
|
expect(hash1).not.toBe(hash2)
|
|
})
|
|
})
|
|
|
|
describe('replaceURL parsing', () => {
|
|
it('should encode and decode nostr links correctly', async () => {
|
|
const { nip19 } = await import('nostr-tools')
|
|
|
|
const npubEncoded = nip19.npubEncode(testPublicKey)
|
|
const decodedNpub = nip19.decode(npubEncoded)
|
|
|
|
expect(decodedNpub.type).toBe('npub')
|
|
expect(decodedNpub.data).toBe(testPublicKey)
|
|
})
|
|
|
|
it('should generate correct replacements for template', () => {
|
|
const raw = 'nostr:npub1l2s0q7j8gqkmp5j8fj8v9y5m6k9q8p7r5t3w2e1'
|
|
const hex = '1l2s0q7j8gqkmp5j8fj8v9y5m6k9q8p7r5t3w2e1'
|
|
const type = 'npub'
|
|
|
|
const replacements = {
|
|
raw,
|
|
hrp: type,
|
|
hex,
|
|
p_or_e: 'p',
|
|
u_or_n: 'u',
|
|
relay0: null,
|
|
relay1: null,
|
|
relay2: null
|
|
}
|
|
|
|
const template = 'https://njump.me/{raw}'
|
|
let result = template
|
|
Object.entries(replacements).forEach(([pattern, value]) => {
|
|
result = result.replace(new RegExp(`{ *${pattern} *}`, 'g'), value)
|
|
})
|
|
|
|
expect(result).toBe(
|
|
'https://njump.me/nostr:npub1l2s0q7j8gqkmp5j8fj8v9y5m6k9q8p7r5t3w2e1'
|
|
)
|
|
})
|
|
})
|
|
})
|