mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2026-09-13 22:05:07 +00:00
fromURI() matched the bunker's response against
`uri.searchParams.get('secret')`, which is `null` when the URI carries no
secret parameter. A bunker answering `{"result": null}` then satisfies
`response.result === null` and is adopted as the client's signer.
Since the client subscribes to the relays named in the URI and the
connection event is public, any participant on those relays can win that
race and sign on the user's behalf.
The secret is the only thing distinguishing the bunker we asked from
everyone else who saw the URI, so treat a missing or empty one as a
programming error and reject before subscribing. createNostrConnectURI()
already always sets it; this only affects URIs built elsewhere.
28 lines
1.1 KiB
TypeScript
28 lines
1.1 KiB
TypeScript
import { test, expect } from 'bun:test'
|
|
|
|
import { BunkerSigner, createNostrConnectURI } from './nip46.ts'
|
|
import { generateSecretKey, getPublicKey } from './pure.ts'
|
|
|
|
const clientSecretKey = generateSecretKey()
|
|
const clientPubkey = getPublicKey(clientSecretKey)
|
|
|
|
test('createNostrConnectURI always includes the secret', () => {
|
|
const uri = new URL(createNostrConnectURI({ clientPubkey, relays: ['wss://relay.example.com'], secret: 'hunter2' }))
|
|
|
|
expect(uri.searchParams.get('secret')).toEqual('hunter2')
|
|
})
|
|
|
|
test('fromURI rejects a URI without a secret', async () => {
|
|
const uri = `nostrconnect://${clientPubkey}?relay=wss://relay.example.com`
|
|
|
|
// otherwise a bunker replying `{"result": null}` would match `get('secret')`
|
|
// and become the signer for this client
|
|
await expect(BunkerSigner.fromURI(clientSecretKey, uri)).rejects.toThrow(/no secret/)
|
|
})
|
|
|
|
test('fromURI rejects a URI with an empty secret', async () => {
|
|
const uri = `nostrconnect://${clientPubkey}?relay=wss://relay.example.com&secret=`
|
|
|
|
await expect(BunkerSigner.fromURI(clientSecretKey, uri)).rejects.toThrow(/no secret/)
|
|
})
|