change tests and nips to use the new api.

This commit is contained in:
fiatjaf 2023-12-19 13:49:03 -03:00
parent 1908e1ee0d
commit fe87529646
No known key found for this signature in database
GPG Key ID: BAD43C4BE5C1A3A1
32 changed files with 151 additions and 163 deletions

View File

@ -19,36 +19,31 @@ If using TypeScript, this package requires TypeScript >= 5.0.
### Generating a private key and a public key ### Generating a private key and a public key
```js ```js
import { generatePrivateKey, getPublicKey } from 'nostr-tools' import { generateSecretKey, getPublicKey } from 'nostr-tools'
let sk = generatePrivateKey() // `sk` is a hex string let sk = generateSecretKey() // `sk` is a hex string
let pk = getPublicKey(sk) // `pk` is a hex string let pk = getPublicKey(sk) // `pk` is a hex string
``` ```
### Creating, signing and verifying events ### Creating, signing and verifying events
```js ```js
import { validateEvent, verifySignature, getSignature, getEventHash, getPublicKey } from 'nostr-tools' import { finalizeEvent, verifyEvent } from 'nostr-tools'
let event = { let event = finalizeEvent({
kind: 1, kind: 1,
created_at: Math.floor(Date.now() / 1000), created_at: Math.floor(Date.now() / 1000),
tags: [], tags: [],
content: 'hello', content: 'hello',
pubkey: getPublicKey(privateKey), }, privateKey)
}
event.id = getEventHash(event) let isGood = verifyEvent(event)
event.sig = getSignature(event, privateKey)
let ok = validateEvent(event)
let veryOk = verifySignature(event)
``` ```
### Interacting with a relay ### Interacting with a relay
```js ```js
import { relayConnect, finishEvent, generatePrivateKey, getPublicKey } from 'nostr-tools' import { relayConnect, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools'
const relay = await relayConnect('wss://relay.example.com') const relay = await relayConnect('wss://relay.example.com')
console.log(`connected to ${relay.url}`) console.log(`connected to ${relay.url}`)
@ -68,7 +63,7 @@ const sub = relay.subscribe([
}) })
// let's publish a new event while simultaneously monitoring the relay for it // let's publish a new event while simultaneously monitoring the relay for it
let sk = generatePrivateKey() let sk = generateSecretKey()
let pk = getPublicKey(sk) let pk = getPublicKey(sk)
let sub = relay.sub([ let sub = relay.sub([
@ -90,7 +85,7 @@ let event = {
} }
// this assigns the pubkey, calculates the event id and signs the event in a single step // this assigns the pubkey, calculates the event id and signs the event in a single step
const signedEvent = finishEvent(event, sk) const signedEvent = finalizeEvent(event, sk)
await relay.publish(signedEvent) await relay.publish(signedEvent)
let events = await relay.list([{ kinds: [0, 1] }]) let events = await relay.list([{ kinds: [0, 1] }])
@ -184,21 +179,21 @@ nip05.useFetchImplementation(require('node-fetch'))
### Encoding and decoding NIP-19 codes ### Encoding and decoding NIP-19 codes
```js ```js
import { nip19, generatePrivateKey, getPublicKey } from 'nostr-tools' import { nip19, generateSecretKey, getPublicKey } from 'nostr-tools'
let sk = generatePrivateKey() let sk = generateSecretKey()
let nsec = nip19.nsecEncode(sk) let nsec = nip19.nsecEncode(sk)
let { type, data } = nip19.decode(nsec) let { type, data } = nip19.decode(nsec)
assert(type === 'nsec') assert(type === 'nsec')
assert(data === sk) assert(data === sk)
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let npub = nip19.npubEncode(pk) let npub = nip19.npubEncode(pk)
let { type, data } = nip19.decode(npub) let { type, data } = nip19.decode(npub)
assert(type === 'npub') assert(type === 'npub')
assert(data === pk) assert(data === pk)
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
let nprofile = nip19.nprofileEncode({ pubkey: pk, relays }) let nprofile = nip19.nprofileEncode({ pubkey: pk, relays })
let { type, data } = nip19.decode(nprofile) let { type, data } = nip19.decode(nprofile)
@ -212,7 +207,7 @@ assert(data.relays.length === 2)
```html ```html
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script> <script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
<script> <script>
window.NostrTools.generatePrivateKey('...') // and so on window.NostrTools.generateSecretKey('...') // and so on
</script> </script>
``` ```

View File

@ -11,10 +11,10 @@ import {
generateSecretKey, generateSecretKey,
} from './pure.ts' } from './pure.ts'
import { ShortTextNote } from './kinds.ts' import { ShortTextNote } from './kinds.ts'
import { hexToBytes } from '@noble/hashes/utils' import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
test('private key generation', () => { test('private key generation', () => {
expect(generateSecretKey()).toMatch(/[a-f0-9]{64}/) expect(bytesToHex(generateSecretKey())).toMatch(/[a-f0-9]{64}/)
}) })
test('public key generation', () => { test('public key generation', () => {
@ -30,7 +30,7 @@ test('public key from private key deterministic', () => {
} }
}) })
describe('finishEvent', () => { describe('finalizeEvent', () => {
test('should create a signed event from a template', () => { test('should create a signed event from a template', () => {
const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf') const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
@ -211,7 +211,7 @@ describe('validateEvent', () => {
}) })
}) })
describe('verifySignature', () => { describe('verifyEvent', () => {
test('should return true for a valid event signature', () => { test('should return true for a valid event signature', () => {
const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf') const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const event = finalizeEvent( const event = finalizeEvent(

View File

@ -1,4 +1,4 @@
import { Event } from './event.ts' import { Event } from './pure.ts'
export type Filter = { export type Filter = {
ids?: string[] ids?: string[]

View File

@ -1,6 +1,6 @@
export * from './keys.ts' export * from './pure.ts'
export * from './relay.ts' export * from './relay.ts'
export * from './event.ts' export * from './pure.ts'
export * from './filter.ts' export * from './filter.ts'
export * from './pool.ts' export * from './pool.ts'
export * from './references.ts' export * from './references.ts'

View File

@ -2,7 +2,8 @@ import { test, expect } from 'bun:test'
import crypto from 'node:crypto' import crypto from 'node:crypto'
import { encrypt, decrypt } from './nip04.ts' import { encrypt, decrypt } from './nip04.ts'
import { getPublicKey, generatePrivateKey } from './keys.ts' import { getPublicKey, generateSecretKey } from './pure.ts'
import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
try { try {
// @ts-ignore // @ts-ignore
@ -13,20 +14,20 @@ try {
} }
test('encrypt and decrypt message', async () => { test('encrypt and decrypt message', async () => {
let sk1 = generatePrivateKey() let sk1 = generateSecretKey()
let sk2 = generatePrivateKey() let sk2 = generateSecretKey()
let pk1 = getPublicKey(sk1) let pk1 = getPublicKey(sk1)
let pk2 = getPublicKey(sk2) let pk2 = getPublicKey(sk2)
let ciphertext = await encrypt(sk1, pk2, 'hello') let ciphertext = await encrypt(bytesToHex(sk1), pk2, 'hello')
expect(await decrypt(sk2, pk1, ciphertext)).toEqual('hello') expect(await decrypt(bytesToHex(sk2), pk1, ciphertext)).toEqual('hello')
}) })
test('decrypt message from go-nostr', async () => { test('decrypt message from go-nostr', async () => {
let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe' let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe'
let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220' let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220'
let pk1 = getPublicKey(sk1) let pk1 = getPublicKey(hexToBytes(sk1))
let ciphertext = 'zJxfaJ32rN5Dg1ODjOlEew==?iv=EV5bUjcc4OX2Km/zPp4ndQ==' let ciphertext = 'zJxfaJ32rN5Dg1ODjOlEew==?iv=EV5bUjcc4OX2Km/zPp4ndQ=='
@ -36,7 +37,7 @@ test('decrypt message from go-nostr', async () => {
test('decrypt big payload from go-nostr', async () => { test('decrypt big payload from go-nostr', async () => {
let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe' let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe'
let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220' let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220'
let pk1 = getPublicKey(sk1) let pk1 = getPublicKey(hexToBytes(sk1))
let ciphertext = let ciphertext =
'6f8dMstm+udOu7yipSn33orTmwQpWbtfuY95NH+eTU1kArysWJIDkYgI2D25EAGIDJsNd45jOJ2NbVOhFiL3ZP/NWsTwXokk34iyHyA/lkjzugQ1bHXoMD1fP/Ay4hB4al1NHb8HXHKZaxPrErwdRDb8qa/I6dXb/1xxyVvNQBHHvmsM5yIFaPwnCN1DZqXf2KbTA/Ekz7Hy+7R+Sy3TXLQDFpWYqykppkXc7Fs0qSuPRyxz5+anuN0dxZa9GTwTEnBrZPbthKkNRrvZMdTGJ6WumOh9aUq8OJJWy9aOgsXvs7qjN1UqcCqQqYaVnEOhCaqWNDsVtsFrVDj+SaLIBvCiomwF4C4nIgngJ5I69tx0UNI0q+ZnvOGQZ7m1PpW2NYP7Yw43HJNdeUEQAmdCPnh/PJwzLTnIxHmQU7n7SPlMdV0SFa6H8y2HHvex697GAkyE5t8c2uO24OnqIwF1tR3blIqXzTSRl0GA6QvrSj2p4UtnWjvF7xT7RiIEyTtgU/AsihTrXyXzWWZaIBJogpgw6erlZqWjCH7sZy/WoGYEiblobOAqMYxax6vRbeuGtoYksr/myX+x9rfLrYuoDRTw4woXOLmMrrj+Mf0TbAgc3SjdkqdsPU1553rlSqIEZXuFgoWmxvVQDtekgTYyS97G81TDSK9nTJT5ilku8NVq2LgtBXGwsNIw/xekcOUzJke3kpnFPutNaexR1VF3ohIuqRKYRGcd8ADJP2lfwMcaGRiplAmFoaVS1YUhQwYFNq9rMLf7YauRGV4BJg/t9srdGxf5RoKCvRo+XM/nLxxysTR9MVaEP/3lDqjwChMxs+eWfLHE5vRWV8hUEqdrWNZV29gsx5nQpzJ4PARGZVu310pQzc6JAlc2XAhhFk6RamkYJnmCSMnb/RblzIATBi2kNrCVAlaXIon188inB62rEpZGPkRIP7PUfu27S/elLQHBHeGDsxOXsBRo1gl3te+raoBHsxo6zvRnYbwdAQa5taDE63eh+fT6kFI+xYmXNAQkU8Dp0MVhEh4JQI06Ni/AKrvYpC95TXXIphZcF+/Pv/vaGkhG2X9S3uhugwWK?iv=2vWkOQQi0WynNJz/aZ4k2g==' '6f8dMstm+udOu7yipSn33orTmwQpWbtfuY95NH+eTU1kArysWJIDkYgI2D25EAGIDJsNd45jOJ2NbVOhFiL3ZP/NWsTwXokk34iyHyA/lkjzugQ1bHXoMD1fP/Ay4hB4al1NHb8HXHKZaxPrErwdRDb8qa/I6dXb/1xxyVvNQBHHvmsM5yIFaPwnCN1DZqXf2KbTA/Ekz7Hy+7R+Sy3TXLQDFpWYqykppkXc7Fs0qSuPRyxz5+anuN0dxZa9GTwTEnBrZPbthKkNRrvZMdTGJ6WumOh9aUq8OJJWy9aOgsXvs7qjN1UqcCqQqYaVnEOhCaqWNDsVtsFrVDj+SaLIBvCiomwF4C4nIgngJ5I69tx0UNI0q+ZnvOGQZ7m1PpW2NYP7Yw43HJNdeUEQAmdCPnh/PJwzLTnIxHmQU7n7SPlMdV0SFa6H8y2HHvex697GAkyE5t8c2uO24OnqIwF1tR3blIqXzTSRl0GA6QvrSj2p4UtnWjvF7xT7RiIEyTtgU/AsihTrXyXzWWZaIBJogpgw6erlZqWjCH7sZy/WoGYEiblobOAqMYxax6vRbeuGtoYksr/myX+x9rfLrYuoDRTw4woXOLmMrrj+Mf0TbAgc3SjdkqdsPU1553rlSqIEZXuFgoWmxvVQDtekgTYyS97G81TDSK9nTJT5ilku8NVq2LgtBXGwsNIw/xekcOUzJke3kpnFPutNaexR1VF3ohIuqRKYRGcd8ADJP2lfwMcaGRiplAmFoaVS1YUhQwYFNq9rMLf7YauRGV4BJg/t9srdGxf5RoKCvRo+XM/nLxxysTR9MVaEP/3lDqjwChMxs+eWfLHE5vRWV8hUEqdrWNZV29gsx5nQpzJ4PARGZVu310pQzc6JAlc2XAhhFk6RamkYJnmCSMnb/RblzIATBi2kNrCVAlaXIon188inB62rEpZGPkRIP7PUfu27S/elLQHBHeGDsxOXsBRo1gl3te+raoBHsxo6zvRnYbwdAQa5taDE63eh+fT6kFI+xYmXNAQkU8Dp0MVhEh4JQI06Ni/AKrvYpC95TXXIphZcF+/Pv/vaGkhG2X9S3uhugwWK?iv=2vWkOQQi0WynNJz/aZ4k2g=='

View File

@ -1,4 +1,4 @@
import { randomBytes } from '@noble/hashes/utils' import { bytesToHex, randomBytes } from '@noble/hashes/utils'
import { secp256k1 } from '@noble/curves/secp256k1' import { secp256k1 } from '@noble/curves/secp256k1'
import { base64 } from '@scure/base' import { base64 } from '@scure/base'
@ -10,7 +10,8 @@ if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) {
crypto.subtle = crypto.webcrypto.subtle crypto.subtle = crypto.webcrypto.subtle
} }
export async function encrypt(privkey: string, pubkey: string, text: string): Promise<string> { export async function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): Promise<string> {
const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey
const key = secp256k1.getSharedSecret(privkey, '02' + pubkey) const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)
const normalizedKey = getNormalizedX(key) const normalizedKey = getNormalizedX(key)
@ -24,7 +25,8 @@ export async function encrypt(privkey: string, pubkey: string, text: string): Pr
return `${ctb64}?iv=${ivb64}` return `${ctb64}?iv=${ivb64}`
} }
export async function decrypt(privkey: string, pubkey: string, data: string): Promise<string> { export async function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): Promise<string> {
const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey
let [ctb64, ivb64] = data.split('?iv=') let [ctb64, ivb64] = data.split('?iv=')
let key = secp256k1.getSharedSecret(privkey, '02' + pubkey) let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)
let normalizedKey = getNormalizedX(key) let normalizedKey = getNormalizedX(key)

View File

@ -1,4 +1,4 @@
import type { Event } from './event.ts' import type { Event } from './pure.ts'
import type { EventPointer, ProfilePointer } from './nip19.ts' import type { EventPointer, ProfilePointer } from './nip19.ts'
export type NIP10Result = { export type NIP10Result = {

View File

@ -1,4 +1,4 @@
import { type UnsignedEvent, type Event, getEventHash } from './event.ts' import { type UnsignedEvent, type Event, getEventHash } from './pure.ts'
/** Get POW difficulty from a Nostr hex ID. */ /** Get POW difficulty from a Nostr hex ID. */
export function getPow(hex: string): number { export function getPow(hex: string): number {

View File

@ -1,6 +1,6 @@
import { describe, test, expect } from 'bun:test' import { describe, test, expect } from 'bun:test'
import { finishEvent } from './event.ts' import { hexToBytes } from '@noble/hashes/utils'
import { getPublicKey } from './keys.ts' import { finalizeEvent, getPublicKey } from './pure.ts'
import { Repost, ShortTextNote } from './kinds.ts' import { Repost, ShortTextNote } from './kinds.ts'
import { finishRepostEvent, getRepostedEventPointer, getRepostedEvent } from './nip18.ts' import { finishRepostEvent, getRepostedEventPointer, getRepostedEvent } from './nip18.ts'
import { buildEvent } from './test-helpers.ts' import { buildEvent } from './test-helpers.ts'
@ -8,11 +8,10 @@ import { buildEvent } from './test-helpers.ts'
const relayUrl = 'https://relay.example.com' const relayUrl = 'https://relay.example.com'
describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => { describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => {
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const repostedEvent = finishEvent( const repostedEvent = finalizeEvent(
{ {
kind: ShortTextNote, kind: ShortTextNote,
tags: [ tags: [

View File

@ -1,4 +1,4 @@
import { Event, finishEvent, verifySignature } from './event.ts' import { Event, finalizeEvent, verifyEvent } from './pure.ts'
import { Repost } from './kinds.ts' import { Repost } from './kinds.ts'
import { EventPointer } from './nip19.ts' import { EventPointer } from './nip19.ts'
@ -23,9 +23,9 @@ export function finishRepostEvent(
t: RepostEventTemplate, t: RepostEventTemplate,
reposted: Event, reposted: Event,
relayUrl: string, relayUrl: string,
privateKey: string, privateKey: Uint8Array,
): Event { ): Event {
return finishEvent( return finalizeEvent(
{ {
kind: Repost, kind: Repost,
tags: [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]], tags: [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]],
@ -89,7 +89,7 @@ export function getRepostedEvent(event: Event, { skipVerification }: GetReposted
return undefined return undefined
} }
if (!skipVerification && !verifySignature(repostedEvent)) { if (!skipVerification && !verifyEvent(repostedEvent)) {
return undefined return undefined
} }

View File

@ -1,5 +1,5 @@
import { test, expect } from 'bun:test' import { test, expect } from 'bun:test'
import { generatePrivateKey, getPublicKey } from './keys.ts' import { generateSecretKey, getPublicKey } from './pure.ts'
import { import {
decode, decode,
naddrEncode, naddrEncode,
@ -14,7 +14,7 @@ import {
} from './nip19.ts' } from './nip19.ts'
test('encode and decode nsec', () => { test('encode and decode nsec', () => {
let sk = generatePrivateKey() let sk = generateSecretKey()
let nsec = nsecEncode(sk) let nsec = nsecEncode(sk)
expect(nsec).toMatch(/nsec1\w+/) expect(nsec).toMatch(/nsec1\w+/)
let { type, data } = decode(nsec) let { type, data } = decode(nsec)
@ -23,7 +23,7 @@ test('encode and decode nsec', () => {
}) })
test('encode and decode npub', () => { test('encode and decode npub', () => {
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let npub = npubEncode(pk) let npub = npubEncode(pk)
expect(npub).toMatch(/npub1\w+/) expect(npub).toMatch(/npub1\w+/)
let { type, data } = decode(npub) let { type, data } = decode(npub)
@ -32,7 +32,7 @@ test('encode and decode npub', () => {
}) })
test('encode and decode nprofile', () => { test('encode and decode nprofile', () => {
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
let nprofile = nprofileEncode({ pubkey: pk, relays }) let nprofile = nprofileEncode({ pubkey: pk, relays })
expect(nprofile).toMatch(/nprofile1\w+/) expect(nprofile).toMatch(/nprofile1\w+/)
@ -56,7 +56,7 @@ test('decode nprofile without relays', () => {
}) })
test('encode and decode naddr', () => { test('encode and decode naddr', () => {
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
let naddr = naddrEncode({ let naddr = naddrEncode({
pubkey: pk, pubkey: pk,
@ -76,7 +76,7 @@ test('encode and decode naddr', () => {
}) })
test('encode and decode nevent', () => { test('encode and decode nevent', () => {
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
let naddr = neventEncode({ let naddr = neventEncode({
id: pk, id: pk,
@ -93,7 +93,7 @@ test('encode and decode nevent', () => {
}) })
test('encode and decode nevent with kind 0', () => { test('encode and decode nevent with kind 0', () => {
let pk = getPublicKey(generatePrivateKey()) let pk = getPublicKey(generateSecretKey())
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com'] let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
let naddr = neventEncode({ let naddr = neventEncode({
id: pk, id: pk,

View File

@ -48,7 +48,7 @@ type Prefixes = {
nrelay: string nrelay: string
nevent: EventPointer nevent: EventPointer
naddr: AddressPointer naddr: AddressPointer
nsec: string nsec: Uint8Array
npub: string npub: string
note: string note: string
} }
@ -130,6 +130,8 @@ export function decode(nip19: string): DecodeResult {
} }
case 'nsec': case 'nsec':
return { type: prefix, data }
case 'npub': case 'npub':
case 'note': case 'note':
return { type: prefix, data: bytesToHex(data) } return { type: prefix, data: bytesToHex(data) }
@ -157,16 +159,16 @@ function parseTLV(data: Uint8Array): TLV {
return result return result
} }
export function nsecEncode(hex: string): `nsec1${string}` { export function nsecEncode(key: Uint8Array): `nsec1${string}` {
return encodeBytes('nsec', hex) return encodeBytes('nsec', key)
} }
export function npubEncode(hex: string): `npub1${string}` { export function npubEncode(hex: string): `npub1${string}` {
return encodeBytes('npub', hex) return encodeBytes('npub', hexToBytes(hex))
} }
export function noteEncode(hex: string): `note1${string}` { export function noteEncode(hex: string): `note1${string}` {
return encodeBytes('note', hex) return encodeBytes('note', hexToBytes(hex))
} }
function encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` { function encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {
@ -174,9 +176,8 @@ function encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array):
return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}` return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`
} }
function encodeBytes<Prefix extends string>(prefix: Prefix, hex: string): `${Prefix}1${string}` { function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {
let data = hexToBytes(hex) return encodeBech32(prefix, bytes)
return encodeBech32(prefix, data)
} }
export function nprofileEncode(profile: ProfilePointer): `nprofile1${string}` { export function nprofileEncode(profile: ProfilePointer): `nprofile1${string}` {

View File

@ -1,15 +1,14 @@
import { describe, test, expect } from 'bun:test' import { describe, test, expect } from 'bun:test'
import { finishEvent } from './event.ts' import { hexToBytes } from '@noble/hashes/utils'
import { getPublicKey } from './keys.ts' import { finalizeEvent, getPublicKey } from './pure.ts'
import { Reaction, ShortTextNote } from './kinds.ts' import { Reaction, ShortTextNote } from './kinds.ts'
import { finishReactionEvent, getReactedEventPointer } from './nip25.ts' import { finishReactionEvent, getReactedEventPointer } from './nip25.ts'
describe('finishReactionEvent + getReactedEventPointer', () => { describe('finishReactionEvent + getReactedEventPointer', () => {
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const reactedEvent = finishEvent( const reactedEvent = finalizeEvent(
{ {
kind: ShortTextNote, kind: ShortTextNote,
tags: [ tags: [

View File

@ -1,4 +1,4 @@
import { Event, finishEvent } from './event.ts' import { Event, finalizeEvent } from './pure.ts'
import { Reaction } from './kinds.ts' import { Reaction } from './kinds.ts'
import type { EventPointer } from './nip19.ts' import type { EventPointer } from './nip19.ts'
@ -17,10 +17,10 @@ export type ReactionEventTemplate = {
created_at: number created_at: number
} }
export function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: string): Event { export function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: Uint8Array): Event {
const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p')) const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))
return finishEvent( return finalizeEvent(
{ {
...t, ...t,
kind: Reaction, kind: Reaction,

View File

@ -1,5 +1,6 @@
import { describe, test, expect } from 'bun:test' import { describe, test, expect } from 'bun:test'
import { getPublicKey } from './keys.ts' import { hexToBytes } from '@noble/hashes/utils'
import { getPublicKey } from './pure.ts'
import * as Kind from './kinds.ts' import * as Kind from './kinds.ts'
import { import {
channelCreateEvent, channelCreateEvent,
@ -11,7 +12,7 @@ import {
ChannelMessageEventTemplate, ChannelMessageEventTemplate,
} from './nip28.ts' } from './nip28.ts'
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf' const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
describe('NIP-28 Functions', () => { describe('NIP-28 Functions', () => {

View File

@ -1,4 +1,4 @@
import { Event, finishEvent } from './event.ts' import { Event, finalizeEvent } from './pure.ts'
import { ChannelCreation, ChannelHideMessage, ChannelMessage, ChannelMetadata, ChannelMuteUser } from './kinds.ts' import { ChannelCreation, ChannelHideMessage, ChannelMessage, ChannelMetadata, ChannelMuteUser } from './kinds.ts'
export interface ChannelMetadata { export interface ChannelMetadata {
@ -45,7 +45,7 @@ export interface ChannelMuteUserEventTemplate {
tags?: string[][] tags?: string[][]
} }
export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: string): Event | undefined => { export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {
let content: string let content: string
if (typeof t.content === 'object') { if (typeof t.content === 'object') {
content = JSON.stringify(t.content) content = JSON.stringify(t.content)
@ -55,7 +55,7 @@ export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: st
return undefined return undefined
} }
return finishEvent( return finalizeEvent(
{ {
kind: ChannelCreation, kind: ChannelCreation,
tags: [...(t.tags ?? [])], tags: [...(t.tags ?? [])],
@ -66,7 +66,7 @@ export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: st
) )
} }
export const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: string): Event | undefined => { export const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {
let content: string let content: string
if (typeof t.content === 'object') { if (typeof t.content === 'object') {
content = JSON.stringify(t.content) content = JSON.stringify(t.content)
@ -76,7 +76,7 @@ export const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey
return undefined return undefined
} }
return finishEvent( return finalizeEvent(
{ {
kind: ChannelMetadata, kind: ChannelMetadata,
tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])], tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],
@ -87,14 +87,14 @@ export const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey
) )
} }
export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: string): Event => { export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {
const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']] const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]
if (t.reply_to_channel_message_event_id) { if (t.reply_to_channel_message_event_id) {
tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply']) tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])
} }
return finishEvent( return finalizeEvent(
{ {
kind: ChannelMessage, kind: ChannelMessage,
tags: [...tags, ...(t.tags ?? [])], tags: [...tags, ...(t.tags ?? [])],
@ -106,7 +106,10 @@ export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey:
} }
/* "e" tag should be the kind 42 event to hide */ /* "e" tag should be the kind 42 event to hide */
export const channelHideMessageEvent = (t: ChannelHideMessageEventTemplate, privateKey: string): Event | undefined => { export const channelHideMessageEvent = (
t: ChannelHideMessageEventTemplate,
privateKey: Uint8Array,
): Event | undefined => {
let content: string let content: string
if (typeof t.content === 'object') { if (typeof t.content === 'object') {
content = JSON.stringify(t.content) content = JSON.stringify(t.content)
@ -116,7 +119,7 @@ export const channelHideMessageEvent = (t: ChannelHideMessageEventTemplate, priv
return undefined return undefined
} }
return finishEvent( return finalizeEvent(
{ {
kind: ChannelHideMessage, kind: ChannelHideMessage,
tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])], tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],
@ -127,7 +130,7 @@ export const channelHideMessageEvent = (t: ChannelHideMessageEventTemplate, priv
) )
} }
export const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: string): Event | undefined => { export const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {
let content: string let content: string
if (typeof t.content === 'object') { if (typeof t.content === 'object') {
content = JSON.stringify(t.content) content = JSON.stringify(t.content)
@ -137,7 +140,7 @@ export const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey
return undefined return undefined
} }
return finishEvent( return finalizeEvent(
{ {
kind: ChannelMuteUser, kind: ChannelMuteUser,
tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])], tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],

View File

@ -1,4 +1,4 @@
import { EventTemplate } from './event.ts' import { EventTemplate } from './pure.ts'
import { ClientAuth } from './kinds.ts' import { ClientAuth } from './kinds.ts'
/** /**

View File

@ -1,7 +1,8 @@
import crypto from 'node:crypto'
import { describe, test, expect } from 'bun:test' import { describe, test, expect } from 'bun:test'
import { hexToBytes } from '@noble/hashes/utils'
import { makeNwcRequestEvent, parseConnectionString } from './nip47' import { makeNwcRequestEvent, parseConnectionString } from './nip47'
import { decrypt } from './nip04.ts' import { decrypt } from './nip04.ts'
import crypto from 'node:crypto'
import { NWCWalletRequest } from './kinds.ts' import { NWCWalletRequest } from './kinds.ts'
// @ts-ignore // @ts-ignore
@ -44,14 +45,10 @@ describe('parseConnectionString', () => {
describe('makeNwcRequestEvent', () => { describe('makeNwcRequestEvent', () => {
test('returns a valid NWC request event', async () => { test('returns a valid NWC request event', async () => {
const pubkey = 'b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4' const pubkey = 'b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4'
const secret = '71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c' const secret = hexToBytes('71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c')
const invoice = const invoice =
'lnbc210n1pjdgyvupp5x43awdarnfd4mdlsklelux0nyckwfu5c708ykuet8vcjnjp3rnpqdqu2askcmr9wssx7e3q2dshgmmndp5scqzzsxqyz5vqsp52l7y9peq9pka3vd3j7aps7gjnalsmy46ndj2mlkz00dltjgqfumq9qyyssq5fasr5dxed8l4qjfnqq48a02jzss3asf8sly7sfaqtr9w3yu2q9spsxhghs3y9aqdf44zkrrg9jjjdg6amade4h0hulllkwk33eqpucp6d5jye' 'lnbc210n1pjdgyvupp5x43awdarnfd4mdlsklelux0nyckwfu5c708ykuet8vcjnjp3rnpqdqu2askcmr9wssx7e3q2dshgmmndp5scqzzsxqyz5vqsp52l7y9peq9pka3vd3j7aps7gjnalsmy46ndj2mlkz00dltjgqfumq9qyyssq5fasr5dxed8l4qjfnqq48a02jzss3asf8sly7sfaqtr9w3yu2q9spsxhghs3y9aqdf44zkrrg9jjjdg6amade4h0hulllkwk33eqpucp6d5jye'
const result = await makeNwcRequestEvent({ const result = await makeNwcRequestEvent(pubkey, secret, invoice)
pubkey,
secret,
invoice,
})
expect(result.kind).toBe(NWCWalletRequest) expect(result.kind).toBe(NWCWalletRequest)
expect(await decrypt(secret, pubkey, result.content)).toEqual( expect(await decrypt(secret, pubkey, result.content)).toEqual(
JSON.stringify({ JSON.stringify({

View File

@ -1,4 +1,4 @@
import { finishEvent } from './event.ts' import { finalizeEvent } from './pure.ts'
import { NWCWalletRequest } from './kinds.ts' import { NWCWalletRequest } from './kinds.ts'
import { encrypt } from './nip04.ts' import { encrypt } from './nip04.ts'
@ -15,22 +15,14 @@ export function parseConnectionString(connectionString: string) {
return { pubkey, relay, secret } return { pubkey, relay, secret }
} }
export async function makeNwcRequestEvent({ export async function makeNwcRequestEvent(pubkey: string, secretKey: Uint8Array, invoice: string) {
pubkey,
secret,
invoice,
}: {
pubkey: string
secret: string
invoice: string
}) {
const content = { const content = {
method: 'pay_invoice', method: 'pay_invoice',
params: { params: {
invoice, invoice,
}, },
} }
const encryptedContent = await encrypt(secret, pubkey, JSON.stringify(content)) const encryptedContent = await encrypt(secretKey, pubkey, JSON.stringify(content))
const eventTemplate = { const eventTemplate = {
kind: NWCWalletRequest, kind: NWCWalletRequest,
created_at: Math.round(Date.now() / 1000), created_at: Math.round(Date.now() / 1000),
@ -38,5 +30,5 @@ export async function makeNwcRequestEvent({
tags: [['p', pubkey]], tags: [['p', pubkey]],
} }
return finishEvent(eventTemplate, secret) return finalizeEvent(eventTemplate, secretKey)
} }

View File

@ -1,6 +1,6 @@
import { describe, test, expect, mock } from 'bun:test' import { describe, test, expect, mock } from 'bun:test'
import { finishEvent } from './event.ts' import { finalizeEvent } from './pure.ts'
import { getPublicKey, generatePrivateKey } from './keys.ts' import { getPublicKey, generateSecretKey } from './pure.ts'
import { getZapEndpoint, makeZapReceipt, makeZapRequest, useFetchImplementation, validateZapRequest } from './nip57.ts' import { getZapEndpoint, makeZapReceipt, makeZapRequest, useFetchImplementation, validateZapRequest } from './nip57.ts'
import { buildEvent } from './test-helpers.ts' import { buildEvent } from './test-helpers.ts'
@ -122,7 +122,7 @@ describe('validateZapRequest', () => {
}) })
test('returns an error message if the signature on the Zap request is invalid', () => { test('returns an error message if the signature on the Zap request is invalid', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = { const zapRequest = {
@ -141,9 +141,8 @@ describe('validateZapRequest', () => {
}) })
test('returns an error message if the Zap request does not have a "p" tag', () => { test('returns an error message if the Zap request does not have a "p" tag', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const zapRequest = finalizeEvent(
const zapRequest = finishEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -160,9 +159,8 @@ describe('validateZapRequest', () => {
}) })
test('returns an error message if the "p" tag on the Zap request is not valid hex', () => { test('returns an error message if the "p" tag on the Zap request is not valid hex', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const zapRequest = finalizeEvent(
const zapRequest = finishEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -180,10 +178,10 @@ describe('validateZapRequest', () => {
}) })
test('returns an error message if the "e" tag on the Zap request is not valid hex', () => { test('returns an error message if the "e" tag on the Zap request is not valid hex', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent( const zapRequest = finalizeEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -202,10 +200,10 @@ describe('validateZapRequest', () => {
}) })
test('returns an error message if the Zap request does not have a relays tag', () => { test('returns an error message if the Zap request does not have a relays tag', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent( const zapRequest = finalizeEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -222,10 +220,10 @@ describe('validateZapRequest', () => {
}) })
test('returns null for a valid Zap request', () => { test('returns null for a valid Zap request', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent( const zapRequest = finalizeEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -245,11 +243,11 @@ describe('validateZapRequest', () => {
describe('makeZapReceipt', () => { describe('makeZapReceipt', () => {
test('returns a valid Zap receipt with a preimage', () => { test('returns a valid Zap receipt with a preimage', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = JSON.stringify( const zapRequest = JSON.stringify(
finishEvent( finalizeEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,
@ -283,11 +281,11 @@ describe('makeZapReceipt', () => {
}) })
test('returns a valid Zap receipt without a preimage', () => { test('returns a valid Zap receipt without a preimage', () => {
const privateKey = generatePrivateKey() const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey) const publicKey = getPublicKey(privateKey)
const zapRequest = JSON.stringify( const zapRequest = JSON.stringify(
finishEvent( finalizeEvent(
{ {
kind: 9734, kind: 9734,
created_at: Date.now() / 1000, created_at: Date.now() / 1000,

View File

@ -1,6 +1,6 @@
import { bech32 } from '@scure/base' import { bech32 } from '@scure/base'
import { validateEvent, verifySignature, type Event, type EventTemplate } from './event.ts' import { validateEvent, verifyEvent, type Event, type EventTemplate } from './pure.ts'
import { utf8Decoder } from './utils.ts' import { utf8Decoder } from './utils.ts'
var _fetch: any var _fetch: any
@ -86,7 +86,7 @@ export function validateZapRequest(zapRequestString: string): string | null {
if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.' if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.'
if (!verifySignature(zapRequest)) return 'Invalid signature on zap request.' if (!verifyEvent(zapRequest)) return 'Invalid signature on zap request.'
let p = zapRequest.tags.find(([t, v]) => t === 'p' && v) let p = zapRequest.tags.find(([t, v]) => t === 'p' && v)
if (!p) return "Zap request doesn't have a 'p' tag." if (!p) return "Zap request doesn't have a 'p' tag."

View File

@ -1,17 +1,17 @@
import { describe, test, expect } from 'bun:test' import { describe, test, expect } from 'bun:test'
import { getToken, unpackEventFromToken, validateEvent, validateToken } from './nip98.ts' import { getToken, unpackEventFromToken, validateEvent, validateToken } from './nip98.ts'
import { Event, finishEvent } from './event.ts' import { Event, finalizeEvent } from './pure.ts'
import { generatePrivateKey, getPublicKey } from './keys.ts' import { generateSecretKey, getPublicKey } from './pure.ts'
import { sha256 } from '@noble/hashes/sha256' import { sha256 } from '@noble/hashes/sha256'
import { utf8Encoder } from './utils.ts' import { utf8Encoder } from './utils.ts'
import { bytesToHex } from '@noble/hashes/utils' import { bytesToHex } from '@noble/hashes/utils'
import { HTTPAuth } from './kinds.ts' import { HTTPAuth } from './kinds.ts'
const sk = generatePrivateKey() const sk = generateSecretKey()
describe('getToken', () => { describe('getToken', () => {
test('getToken GET returns without authorization scheme', async () => { test('getToken GET returns without authorization scheme', async () => {
let result = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) let result = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const decodedResult: Event = await unpackEventFromToken(result) const decodedResult: Event = await unpackEventFromToken(result)
@ -26,7 +26,7 @@ describe('getToken', () => {
}) })
test('getToken POST returns token without authorization scheme', async () => { test('getToken POST returns token without authorization scheme', async () => {
let result = await getToken('http://test.com', 'post', e => finishEvent(e, sk)) let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk))
const decodedResult: Event = await unpackEventFromToken(result) const decodedResult: Event = await unpackEventFromToken(result)
@ -43,7 +43,7 @@ describe('getToken', () => {
test('getToken GET returns token WITH authorization scheme', async () => { test('getToken GET returns token WITH authorization scheme', async () => {
const authorizationScheme = 'Nostr ' const authorizationScheme = 'Nostr '
let result = await getToken('http://test.com', 'post', e => finishEvent(e, sk), true) let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true)
expect(result.startsWith(authorizationScheme)).toBe(true) expect(result.startsWith(authorizationScheme)).toBe(true)
@ -62,7 +62,7 @@ describe('getToken', () => {
test('getToken returns token with a valid payload tag when payload is present', async () => { test('getToken returns token with a valid payload tag when payload is present', async () => {
const payload = { test: 'payload' } const payload = { test: 'payload' }
const payloadHash = bytesToHex(sha256(utf8Encoder.encode(JSON.stringify(payload)))) const payloadHash = bytesToHex(sha256(utf8Encoder.encode(JSON.stringify(payload))))
let result = await getToken('http://test.com', 'post', e => finishEvent(e, sk), true, payload) let result = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, payload)
const decodedResult: Event = await unpackEventFromToken(result) const decodedResult: Event = await unpackEventFromToken(result)
@ -80,14 +80,14 @@ describe('getToken', () => {
describe('validateToken', () => { describe('validateToken', () => {
test('validateToken returns true for valid token without authorization scheme', async () => { test('validateToken returns true for valid token without authorization scheme', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const result = await validateToken(validToken, 'http://test.com', 'get') const result = await validateToken(validToken, 'http://test.com', 'get')
expect(result).toBe(true) expect(result).toBe(true)
}) })
test('validateToken returns true for valid token with authorization scheme', async () => { test('validateToken returns true for valid token with authorization scheme', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const result = await validateToken(validToken, 'http://test.com', 'get') const result = await validateToken(validToken, 'http://test.com', 'get')
expect(result).toBe(true) expect(result).toBe(true)
@ -104,21 +104,21 @@ describe('validateToken', () => {
}) })
test('validateToken throws an error for a wrong url', async () => { test('validateToken throws an error for a wrong url', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const result = validateToken(validToken, 'http://wrong-test.com', 'get') const result = validateToken(validToken, 'http://wrong-test.com', 'get')
expect(result).rejects.toThrow(Error) expect(result).rejects.toThrow(Error)
}) })
test('validateToken throws an error for a wrong method', async () => { test('validateToken throws an error for a wrong method', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk)) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk))
const result = validateToken(validToken, 'http://test.com', 'post') const result = validateToken(validToken, 'http://test.com', 'post')
expect(result).rejects.toThrow(Error) expect(result).rejects.toThrow(Error)
}) })
test('validateEvent returns true for valid decoded token with authorization scheme', async () => { test('validateEvent returns true for valid decoded token with authorization scheme', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const decodedResult: Event = await unpackEventFromToken(validToken) const decodedResult: Event = await unpackEventFromToken(validToken)
const result = await validateEvent(decodedResult, 'http://test.com', 'get') const result = await validateEvent(decodedResult, 'http://test.com', 'get')
@ -126,7 +126,7 @@ describe('validateToken', () => {
}) })
test('validateEvent throws an error for a wrong url', async () => { test('validateEvent throws an error for a wrong url', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const decodedResult: Event = await unpackEventFromToken(validToken) const decodedResult: Event = await unpackEventFromToken(validToken)
const result = validateEvent(decodedResult, 'http://wrong-test.com', 'get') const result = validateEvent(decodedResult, 'http://wrong-test.com', 'get')
@ -134,7 +134,7 @@ describe('validateToken', () => {
}) })
test('validateEvent throws an error for a wrong method', async () => { test('validateEvent throws an error for a wrong method', async () => {
const validToken = await getToken('http://test.com', 'get', e => finishEvent(e, sk), true) const validToken = await getToken('http://test.com', 'get', e => finalizeEvent(e, sk), true)
const decodedResult: Event = await unpackEventFromToken(validToken) const decodedResult: Event = await unpackEventFromToken(validToken)
const result = validateEvent(decodedResult, 'http://test.com', 'post') const result = validateEvent(decodedResult, 'http://test.com', 'post')
@ -142,7 +142,7 @@ describe('validateToken', () => {
}) })
test('validateEvent returns true for valid payload tag hash', async () => { test('validateEvent returns true for valid payload tag hash', async () => {
const validToken = await getToken('http://test.com', 'post', e => finishEvent(e, sk), true, { test: 'payload' }) const validToken = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'payload' })
const decodedResult: Event = await unpackEventFromToken(validToken) const decodedResult: Event = await unpackEventFromToken(validToken)
const result = await validateEvent(decodedResult, 'http://test.com', 'post', { test: 'payload' }) const result = await validateEvent(decodedResult, 'http://test.com', 'post', { test: 'payload' })
@ -150,7 +150,7 @@ describe('validateToken', () => {
}) })
test('validateEvent returns false for invalid payload tag hash', async () => { test('validateEvent returns false for invalid payload tag hash', async () => {
const validToken = await getToken('http://test.com', 'post', e => finishEvent(e, sk), true, { test: 'a-payload' }) const validToken = await getToken('http://test.com', 'post', e => finalizeEvent(e, sk), true, { test: 'a-payload' })
const decodedResult: Event = await unpackEventFromToken(validToken) const decodedResult: Event = await unpackEventFromToken(validToken)
const result = validateEvent(decodedResult, 'http://test.com', 'post', { test: 'a-different-payload' }) const result = validateEvent(decodedResult, 'http://test.com', 'post', { test: 'a-different-payload' })

View File

@ -1,9 +1,9 @@
import { bytesToHex } from '@noble/hashes/utils' import { bytesToHex } from '@noble/hashes/utils'
import { sha256 } from '@noble/hashes/sha256' import { sha256 } from '@noble/hashes/sha256'
import { base64 } from '@scure/base' import { base64 } from '@scure/base'
import { Event, EventTemplate, verifySignature } from './event' import { Event, EventTemplate, verifyEvent } from './pure.ts'
import { utf8Decoder, utf8Encoder } from './utils' import { utf8Decoder, utf8Encoder } from './utils.ts'
import { HTTPAuth } from './kinds' import { HTTPAuth } from './kinds.ts'
const _authorizationScheme = 'Nostr ' const _authorizationScheme = 'Nostr '
@ -83,7 +83,7 @@ export async function validateEvent(event: Event, url: string, method: string, b
if (!event) { if (!event) {
throw new Error('Invalid nostr event') throw new Error('Invalid nostr event')
} }
if (!verifySignature(event)) { if (!verifyEvent(event)) {
throw new Error('Invalid nostr event, signature invalid') throw new Error('Invalid nostr event, signature invalid')
} }
if (event.kind !== HTTPAuth) { if (event.kind !== HTTPAuth) {

View File

@ -1,7 +1,7 @@
import { test, expect, afterAll } from 'bun:test' import { test, expect, afterAll } from 'bun:test'
import { finishEvent, type Event } from './event.ts' import { finalizeEvent, type Event } from './pure.ts'
import { generatePrivateKey, getPublicKey } from './keys.ts' import { generateSecretKey, getPublicKey } from './pure.ts'
import { SimplePool } from './pool.ts' import { SimplePool } from './pool.ts'
let pool = new SimplePool() let pool = new SimplePool()
@ -13,7 +13,7 @@ afterAll(() => {
}) })
test('removing duplicates when querying', async () => { test('removing duplicates when querying', async () => {
let priv = generatePrivateKey() let priv = generateSecretKey()
let pub = getPublicKey(priv) let pub = getPublicKey(priv)
pool.subscribeMany(relays, [{ authors: [pub] }], { pool.subscribeMany(relays, [{ authors: [pub] }], {
@ -26,7 +26,7 @@ test('removing duplicates when querying', async () => {
}) })
let received: Event[] = [] let received: Event[] = []
let event = finishEvent( let event = finalizeEvent(
{ {
created_at: Math.round(Date.now() / 1000), created_at: Math.round(Date.now() / 1000),
content: 'test', content: 'test',
@ -44,7 +44,7 @@ test('removing duplicates when querying', async () => {
}) })
test('same with double querying', async () => { test('same with double querying', async () => {
let priv = generatePrivateKey() let priv = generateSecretKey()
let pub = getPublicKey(priv) let pub = getPublicKey(priv)
pool.subscribeMany(relays, [{ authors: [pub] }], { pool.subscribeMany(relays, [{ authors: [pub] }], {
@ -60,7 +60,7 @@ test('same with double querying', async () => {
let received: Event[] = [] let received: Event[] = []
let event = finishEvent( let event = finalizeEvent(
{ {
created_at: Math.round(Date.now() / 1000), created_at: Math.round(Date.now() / 1000),
content: 'test2', content: 'test2',

View File

@ -1,7 +1,7 @@
import { Relay, SubscriptionParams, Subscription } from './relay.ts' import { Relay, SubscriptionParams, Subscription } from './relay.ts'
import { normalizeURL } from './utils.ts' import { normalizeURL } from './utils.ts'
import type { Event } from './event.ts' import type { Event } from './pure.ts'
import { type Filter } from './filter.ts' import { type Filter } from './filter.ts'
export type SubCloser = { close: () => void } export type SubCloser = { close: () => void }
@ -103,7 +103,7 @@ export class SimplePool {
return return
} }
let subscription = await relay.subscribe(filters, { let subscription = relay.subscribe(filters, {
...params, ...params,
oneose: () => handleEose(i), oneose: () => handleEose(i),
onclose: reason => handleClose(i, reason), onclose: reason => handleClose(i, reason),

View File

@ -14,7 +14,7 @@ class JS implements Nostr {
} }
finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent { finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {
const event = t as VerifiedEvent const event = t as VerifiedEvent
event.pubkey = this.getPublicKey(secretKey) event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))
event.id = getEventHash(event) event.id = getEventHash(event)
event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey)) event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))
event[verifiedSymbol] = true event[verifiedSymbol] = true

View File

@ -1,6 +1,6 @@
import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts' import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'
import type { Event } from './event.ts' import type { Event } from './pure.ts'
type Reference = { type Reference = {
text: string text: string

View File

@ -1,7 +1,7 @@
import { test, expect, afterEach, beforeEach } from 'bun:test' import { test, expect, afterEach, beforeEach } from 'bun:test'
import { finishEvent } from './event.ts' import { finalizeEvent } from './pure.ts'
import { generatePrivateKey, getPublicKey } from './keys.ts' import { generateSecretKey, getPublicKey } from './pure.ts'
import { Relay } from './relay.ts' import { Relay } from './relay.ts'
let relay = new Relay('wss://public.relaying.io') let relay = new Relay('wss://public.relaying.io')
@ -57,7 +57,7 @@ test('querying', async () => {
}, 10000) }, 10000)
test('listening and publishing and closing', async () => { test('listening and publishing and closing', async () => {
let sk = generatePrivateKey() let sk = generateSecretKey()
let pk = getPublicKey(sk) let pk = getPublicKey(sk)
var resolve1: (_: void) => void var resolve1: (_: void) => void
var resolve2: (_: void) => void var resolve2: (_: void) => void
@ -91,7 +91,7 @@ test('listening and publishing and closing', async () => {
}, },
) )
let event = finishEvent( let event = finalizeEvent(
{ {
kind: 23571, kind: 23571,
created_at: Math.floor(Date.now() / 1000), created_at: Math.floor(Date.now() / 1000),

View File

@ -1,6 +1,6 @@
/* global WebSocket */ /* global WebSocket */
import { verifySignature, validateEvent, type Event, EventTemplate } from './event.ts' import { verifyEvent, validateEvent, type Event, EventTemplate } from './pure.ts'
import { matchFilters, type Filter } from './filter.ts' import { matchFilters, type Filter } from './filter.ts'
import { getHex64, getSubscriptionId } from './fakejson.ts' import { getHex64, getSubscriptionId } from './fakejson.ts'
import { Queue, normalizeURL } from './utils.ts' import { Queue, normalizeURL } from './utils.ts'
@ -161,7 +161,7 @@ export class Relay {
case 'EVENT': { case 'EVENT': {
const so = this.openSubs.get(data[1] as string) as Subscription const so = this.openSubs.get(data[1] as string) as Subscription
const event = data[2] as Event const event = data[2] as Event
if ((this.trusted || (validateEvent(event) && verifySignature(event))) && matchFilters(so.filters, event)) { if ((this.trusted || (validateEvent(event) && verifyEvent(event))) && matchFilters(so.filters, event)) {
so.onevent(event) so.onevent(event)
} }
return return

View File

@ -1,4 +1,4 @@
import type { Event } from './event.ts' import type { Event } from './pure.ts'
/** Build an event for testing purposes. */ /** Build an event for testing purposes. */
export function buildEvent(params: Partial<Event>): Event { export function buildEvent(params: Partial<Event>): Event {

View File

@ -2,7 +2,7 @@ import { describe, test, expect } from 'bun:test'
import { buildEvent } from './test-helpers.ts' import { buildEvent } from './test-helpers.ts'
import { Queue, insertEventIntoAscendingList, insertEventIntoDescendingList, binarySearch } from './utils.ts' import { Queue, insertEventIntoAscendingList, insertEventIntoDescendingList, binarySearch } from './utils.ts'
import type { Event } from './event.ts' import type { Event } from './pure.ts'
describe('inserting into a desc sorted list of events', () => { describe('inserting into a desc sorted list of events', () => {
test('insert into an empty list', async () => { test('insert into an empty list', async () => {

View File

@ -1,4 +1,4 @@
import type { Event } from './event.ts' import type { Event } from './pure.ts'
export const utf8Decoder = new TextDecoder('utf-8') export const utf8Decoder = new TextDecoder('utf-8')
export const utf8Encoder = new TextEncoder() export const utf8Encoder = new TextEncoder()