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
```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
```
### Creating, signing and verifying events
```js
import { validateEvent, verifySignature, getSignature, getEventHash, getPublicKey } from 'nostr-tools'
import { finalizeEvent, verifyEvent } from 'nostr-tools'
let event = {
let event = finalizeEvent({
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'hello',
pubkey: getPublicKey(privateKey),
}
}, privateKey)
event.id = getEventHash(event)
event.sig = getSignature(event, privateKey)
let ok = validateEvent(event)
let veryOk = verifySignature(event)
let isGood = verifyEvent(event)
```
### Interacting with a relay
```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')
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 sk = generatePrivateKey()
let sk = generateSecretKey()
let pk = getPublicKey(sk)
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
const signedEvent = finishEvent(event, sk)
const signedEvent = finalizeEvent(event, sk)
await relay.publish(signedEvent)
let events = await relay.list([{ kinds: [0, 1] }])
@ -184,21 +179,21 @@ nip05.useFetchImplementation(require('node-fetch'))
### Encoding and decoding NIP-19 codes
```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 { type, data } = nip19.decode(nsec)
assert(type === 'nsec')
assert(data === sk)
let pk = getPublicKey(generatePrivateKey())
let pk = getPublicKey(generateSecretKey())
let npub = nip19.npubEncode(pk)
let { type, data } = nip19.decode(npub)
assert(type === 'npub')
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 nprofile = nip19.nprofileEncode({ pubkey: pk, relays })
let { type, data } = nip19.decode(nprofile)
@ -212,7 +207,7 @@ assert(data.relays.length === 2)
```html
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
<script>
window.NostrTools.generatePrivateKey('...') // and so on
window.NostrTools.generateSecretKey('...') // and so on
</script>
```

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@ import { test, expect } from 'bun:test'
import crypto from 'node:crypto'
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 {
// @ts-ignore
@ -13,20 +14,20 @@ try {
}
test('encrypt and decrypt message', async () => {
let sk1 = generatePrivateKey()
let sk2 = generatePrivateKey()
let sk1 = generateSecretKey()
let sk2 = generateSecretKey()
let pk1 = getPublicKey(sk1)
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 () => {
let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe'
let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220'
let pk1 = getPublicKey(sk1)
let pk1 = getPublicKey(hexToBytes(sk1))
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 () => {
let sk1 = '91ba716fa9e7ea2fcbad360cf4f8e0d312f73984da63d90f524ad61a6a1e7dbe'
let sk2 = '96f6fa197aa07477ab88f6981118466ae3a982faab8ad5db9d5426870c73d220'
let pk1 = getPublicKey(sk1)
let pk1 = getPublicKey(hexToBytes(sk1))
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=='

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 { base64 } from '@scure/base'
@ -10,7 +10,8 @@ if (typeof crypto !== 'undefined' && !crypto.subtle && crypto.webcrypto) {
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 normalizedKey = getNormalizedX(key)
@ -24,7 +25,8 @@ export async function encrypt(privkey: string, pubkey: string, text: string): Pr
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 key = secp256k1.getSharedSecret(privkey, '02' + pubkey)
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'
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. */
export function getPow(hex: string): number {

View File

@ -1,6 +1,6 @@
import { describe, test, expect } from 'bun:test'
import { finishEvent } from './event.ts'
import { getPublicKey } from './keys.ts'
import { hexToBytes } from '@noble/hashes/utils'
import { finalizeEvent, getPublicKey } from './pure.ts'
import { Repost, ShortTextNote } from './kinds.ts'
import { finishRepostEvent, getRepostedEventPointer, getRepostedEvent } from './nip18.ts'
import { buildEvent } from './test-helpers.ts'
@ -8,11 +8,10 @@ import { buildEvent } from './test-helpers.ts'
const relayUrl = 'https://relay.example.com'
describe('finishRepostEvent + getRepostedEventPointer + getRepostedEvent', () => {
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf'
const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey)
const repostedEvent = finishEvent(
const repostedEvent = finalizeEvent(
{
kind: ShortTextNote,
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 { EventPointer } from './nip19.ts'
@ -23,9 +23,9 @@ export function finishRepostEvent(
t: RepostEventTemplate,
reposted: Event,
relayUrl: string,
privateKey: string,
privateKey: Uint8Array,
): Event {
return finishEvent(
return finalizeEvent(
{
kind: Repost,
tags: [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]],
@ -89,7 +89,7 @@ export function getRepostedEvent(event: Event, { skipVerification }: GetReposted
return undefined
}
if (!skipVerification && !verifySignature(repostedEvent)) {
if (!skipVerification && !verifyEvent(repostedEvent)) {
return undefined
}

View File

@ -1,5 +1,5 @@
import { test, expect } from 'bun:test'
import { generatePrivateKey, getPublicKey } from './keys.ts'
import { generateSecretKey, getPublicKey } from './pure.ts'
import {
decode,
naddrEncode,
@ -14,7 +14,7 @@ import {
} from './nip19.ts'
test('encode and decode nsec', () => {
let sk = generatePrivateKey()
let sk = generateSecretKey()
let nsec = nsecEncode(sk)
expect(nsec).toMatch(/nsec1\w+/)
let { type, data } = decode(nsec)
@ -23,7 +23,7 @@ test('encode and decode nsec', () => {
})
test('encode and decode npub', () => {
let pk = getPublicKey(generatePrivateKey())
let pk = getPublicKey(generateSecretKey())
let npub = npubEncode(pk)
expect(npub).toMatch(/npub1\w+/)
let { type, data } = decode(npub)
@ -32,7 +32,7 @@ test('encode and decode npub', () => {
})
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 nprofile = nprofileEncode({ pubkey: pk, relays })
expect(nprofile).toMatch(/nprofile1\w+/)
@ -56,7 +56,7 @@ test('decode nprofile without relays', () => {
})
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 naddr = naddrEncode({
pubkey: pk,
@ -76,7 +76,7 @@ test('encode and decode naddr', () => {
})
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 naddr = neventEncode({
id: pk,
@ -93,7 +93,7 @@ test('encode and decode nevent', () => {
})
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 naddr = neventEncode({
id: pk,

View File

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

View File

@ -1,15 +1,14 @@
import { describe, test, expect } from 'bun:test'
import { finishEvent } from './event.ts'
import { getPublicKey } from './keys.ts'
import { hexToBytes } from '@noble/hashes/utils'
import { finalizeEvent, getPublicKey } from './pure.ts'
import { Reaction, ShortTextNote } from './kinds.ts'
import { finishReactionEvent, getReactedEventPointer } from './nip25.ts'
describe('finishReactionEvent + getReactedEventPointer', () => {
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf'
const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey)
const reactedEvent = finishEvent(
const reactedEvent = finalizeEvent(
{
kind: ShortTextNote,
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 type { EventPointer } from './nip19.ts'
@ -17,10 +17,10 @@ export type ReactionEventTemplate = {
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'))
return finishEvent(
return finalizeEvent(
{
...t,
kind: Reaction,

View File

@ -1,5 +1,6 @@
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 {
channelCreateEvent,
@ -11,7 +12,7 @@ import {
ChannelMessageEventTemplate,
} from './nip28.ts'
const privateKey = 'd217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf'
const privateKey = hexToBytes('d217c1ff2f8a65c3e3a1740db3b9f58b8c848bb45e26d00ed4714e4a0f4ceecf')
const publicKey = getPublicKey(privateKey)
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'
export interface ChannelMetadata {
@ -45,7 +45,7 @@ export interface ChannelMuteUserEventTemplate {
tags?: string[][]
}
export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: string): Event | undefined => {
export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {
let content: string
if (typeof t.content === 'object') {
content = JSON.stringify(t.content)
@ -55,7 +55,7 @@ export const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: st
return undefined
}
return finishEvent(
return finalizeEvent(
{
kind: ChannelCreation,
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
if (typeof t.content === 'object') {
content = JSON.stringify(t.content)
@ -76,7 +76,7 @@ export const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey
return undefined
}
return finishEvent(
return finalizeEvent(
{
kind: ChannelMetadata,
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']]
if (t.reply_to_channel_message_event_id) {
tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])
}
return finishEvent(
return finalizeEvent(
{
kind: ChannelMessage,
tags: [...tags, ...(t.tags ?? [])],
@ -106,7 +106,10 @@ export const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey:
}
/* "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
if (typeof t.content === 'object') {
content = JSON.stringify(t.content)
@ -116,7 +119,7 @@ export const channelHideMessageEvent = (t: ChannelHideMessageEventTemplate, priv
return undefined
}
return finishEvent(
return finalizeEvent(
{
kind: ChannelHideMessage,
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
if (typeof t.content === 'object') {
content = JSON.stringify(t.content)
@ -137,7 +140,7 @@ export const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey
return undefined
}
return finishEvent(
return finalizeEvent(
{
kind: ChannelMuteUser,
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'
/**

View File

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

View File

@ -1,4 +1,4 @@
import { finishEvent } from './event.ts'
import { finalizeEvent } from './pure.ts'
import { NWCWalletRequest } from './kinds.ts'
import { encrypt } from './nip04.ts'
@ -15,22 +15,14 @@ export function parseConnectionString(connectionString: string) {
return { pubkey, relay, secret }
}
export async function makeNwcRequestEvent({
pubkey,
secret,
invoice,
}: {
pubkey: string
secret: string
invoice: string
}) {
export async function makeNwcRequestEvent(pubkey: string, secretKey: Uint8Array, invoice: string) {
const content = {
method: 'pay_invoice',
params: {
invoice,
},
}
const encryptedContent = await encrypt(secret, pubkey, JSON.stringify(content))
const encryptedContent = await encrypt(secretKey, pubkey, JSON.stringify(content))
const eventTemplate = {
kind: NWCWalletRequest,
created_at: Math.round(Date.now() / 1000),
@ -38,5 +30,5 @@ export async function makeNwcRequestEvent({
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 { finishEvent } from './event.ts'
import { getPublicKey, generatePrivateKey } from './keys.ts'
import { finalizeEvent } from './pure.ts'
import { getPublicKey, generateSecretKey } from './pure.ts'
import { getZapEndpoint, makeZapReceipt, makeZapRequest, useFetchImplementation, validateZapRequest } from './nip57.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', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = {
@ -141,9 +141,8 @@ describe('validateZapRequest', () => {
})
test('returns an error message if the Zap request does not have a "p" tag', () => {
const privateKey = generatePrivateKey()
const zapRequest = finishEvent(
const privateKey = generateSecretKey()
const zapRequest = finalizeEvent(
{
kind: 9734,
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', () => {
const privateKey = generatePrivateKey()
const zapRequest = finishEvent(
const privateKey = generateSecretKey()
const zapRequest = finalizeEvent(
{
kind: 9734,
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', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent(
const zapRequest = finalizeEvent(
{
kind: 9734,
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', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent(
const zapRequest = finalizeEvent(
{
kind: 9734,
created_at: Date.now() / 1000,
@ -222,10 +220,10 @@ describe('validateZapRequest', () => {
})
test('returns null for a valid Zap request', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = finishEvent(
const zapRequest = finalizeEvent(
{
kind: 9734,
created_at: Date.now() / 1000,
@ -245,11 +243,11 @@ describe('validateZapRequest', () => {
describe('makeZapReceipt', () => {
test('returns a valid Zap receipt with a preimage', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = JSON.stringify(
finishEvent(
finalizeEvent(
{
kind: 9734,
created_at: Date.now() / 1000,
@ -283,11 +281,11 @@ describe('makeZapReceipt', () => {
})
test('returns a valid Zap receipt without a preimage', () => {
const privateKey = generatePrivateKey()
const privateKey = generateSecretKey()
const publicKey = getPublicKey(privateKey)
const zapRequest = JSON.stringify(
finishEvent(
finalizeEvent(
{
kind: 9734,
created_at: Date.now() / 1000,

View File

@ -1,6 +1,6 @@
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'
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 (!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)
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 { getToken, unpackEventFromToken, validateEvent, validateToken } from './nip98.ts'
import { Event, finishEvent } from './event.ts'
import { generatePrivateKey, getPublicKey } from './keys.ts'
import { Event, finalizeEvent } from './pure.ts'
import { generateSecretKey, getPublicKey } from './pure.ts'
import { sha256 } from '@noble/hashes/sha256'
import { utf8Encoder } from './utils.ts'
import { bytesToHex } from '@noble/hashes/utils'
import { HTTPAuth } from './kinds.ts'
const sk = generatePrivateKey()
const sk = generateSecretKey()
describe('getToken', () => {
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)
@ -26,7 +26,7 @@ describe('getToken', () => {
})
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)
@ -43,7 +43,7 @@ describe('getToken', () => {
test('getToken GET returns token WITH authorization scheme', async () => {
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)
@ -62,7 +62,7 @@ describe('getToken', () => {
test('getToken returns token with a valid payload tag when payload is present', async () => {
const payload = { test: '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)
@ -80,14 +80,14 @@ describe('getToken', () => {
describe('validateToken', () => {
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')
expect(result).toBe(true)
})
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')
expect(result).toBe(true)
@ -104,21 +104,21 @@ describe('validateToken', () => {
})
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')
expect(result).rejects.toThrow(Error)
})
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')
expect(result).rejects.toThrow(Error)
})
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 result = await validateEvent(decodedResult, 'http://test.com', 'get')
@ -126,7 +126,7 @@ describe('validateToken', () => {
})
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 result = validateEvent(decodedResult, 'http://wrong-test.com', 'get')
@ -134,7 +134,7 @@ describe('validateToken', () => {
})
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 result = validateEvent(decodedResult, 'http://test.com', 'post')
@ -142,7 +142,7 @@ describe('validateToken', () => {
})
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 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 () => {
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 result = validateEvent(decodedResult, 'http://test.com', 'post', { test: 'a-different-payload' })

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
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 = {
text: string

View File

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

View File

@ -1,6 +1,6 @@
/* 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 { getHex64, getSubscriptionId } from './fakejson.ts'
import { Queue, normalizeURL } from './utils.ts'
@ -161,7 +161,7 @@ export class Relay {
case 'EVENT': {
const so = this.openSubs.get(data[1] as string) as Subscription
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)
}
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. */
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 { 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', () => {
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 utf8Encoder = new TextEncoder()