mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 00:28:51 +00:00
remove all the NIP-26 stuff.
This commit is contained in:
37
README.md
37
README.md
@@ -258,43 +258,6 @@ sub.on('event', async event => {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Performing and checking for delegation
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { nip26, getPublicKey, generatePrivateKey } from 'nostr-tools'
|
|
||||||
|
|
||||||
// delegator
|
|
||||||
let sk1 = generatePrivateKey()
|
|
||||||
let pk1 = getPublicKey(sk1)
|
|
||||||
|
|
||||||
// delegatee
|
|
||||||
let sk2 = generatePrivateKey()
|
|
||||||
let pk2 = getPublicKey(sk2)
|
|
||||||
|
|
||||||
// generate delegation
|
|
||||||
let delegation = nip26.createDelegation(sk1, {
|
|
||||||
pubkey: pk2,
|
|
||||||
kind: 1,
|
|
||||||
since: Math.round(Date.now() / 1000),
|
|
||||||
until: Math.round(Date.now() / 1000) + 60 * 60 * 24 * 30 /* 30 days */,
|
|
||||||
})
|
|
||||||
|
|
||||||
// the delegatee uses the delegation when building an event
|
|
||||||
let event = {
|
|
||||||
pubkey: pk2,
|
|
||||||
kind: 1,
|
|
||||||
created_at: Math.round(Date.now() / 1000),
|
|
||||||
content: 'hello from a delegated key',
|
|
||||||
tags: [['delegation', delegation.from, delegation.cond, delegation.sig]],
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally any receiver of this event can check for the presence of a valid delegation tag
|
|
||||||
let delegator = nip26.getDelegator(event)
|
|
||||||
assert(delegator === pk1) // will be null if there is no delegation tag or if it is invalid
|
|
||||||
```
|
|
||||||
|
|
||||||
Please consult the tests or [the source code](https://github.com/fiatjaf/nostr-tools) for more information that isn't available here.
|
|
||||||
|
|
||||||
### Using from the browser (if you don't want to use a bundler)
|
### Using from the browser (if you don't want to use a bundler)
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
|||||||
1
index.ts
1
index.ts
@@ -13,7 +13,6 @@ export * as nip18 from './nip18.ts'
|
|||||||
export * as nip19 from './nip19.ts'
|
export * as nip19 from './nip19.ts'
|
||||||
export * as nip21 from './nip21.ts'
|
export * as nip21 from './nip21.ts'
|
||||||
export * as nip25 from './nip25.ts'
|
export * as nip25 from './nip25.ts'
|
||||||
export * as nip26 from './nip26.ts'
|
|
||||||
export * as nip27 from './nip27.ts'
|
export * as nip27 from './nip27.ts'
|
||||||
export * as nip28 from './nip28.ts'
|
export * as nip28 from './nip28.ts'
|
||||||
export * as nip39 from './nip39.ts'
|
export * as nip39 from './nip39.ts'
|
||||||
|
|||||||
101
nip26.test.ts
101
nip26.test.ts
@@ -1,101 +0,0 @@
|
|||||||
import { getPublicKey, generatePrivateKey } from './keys.ts'
|
|
||||||
import { getDelegator, createDelegation } from './nip26.ts'
|
|
||||||
import { buildEvent } from './test-helpers.ts'
|
|
||||||
|
|
||||||
test('parse good delegation from NIP', async () => {
|
|
||||||
expect(
|
|
||||||
getDelegator({
|
|
||||||
id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc',
|
|
||||||
pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49',
|
|
||||||
created_at: 1660896109,
|
|
||||||
kind: 1,
|
|
||||||
tags: [
|
|
||||||
[
|
|
||||||
'delegation',
|
|
||||||
'86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e',
|
|
||||||
'kind=1&created_at>1640995200',
|
|
||||||
'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
content: 'Hello world',
|
|
||||||
sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6',
|
|
||||||
}),
|
|
||||||
).toEqual('86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('parse bad delegations', async () => {
|
|
||||||
expect(
|
|
||||||
getDelegator({
|
|
||||||
id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc',
|
|
||||||
pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49',
|
|
||||||
created_at: 1660896109,
|
|
||||||
kind: 1,
|
|
||||||
tags: [
|
|
||||||
[
|
|
||||||
'delegation',
|
|
||||||
'86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42f',
|
|
||||||
'kind=1&created_at>1640995200',
|
|
||||||
'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
content: 'Hello world',
|
|
||||||
sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6',
|
|
||||||
}),
|
|
||||||
).toEqual(null)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getDelegator({
|
|
||||||
id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc',
|
|
||||||
pubkey: '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49',
|
|
||||||
created_at: 1660896109,
|
|
||||||
kind: 1,
|
|
||||||
tags: [
|
|
||||||
[
|
|
||||||
'delegation',
|
|
||||||
'86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e',
|
|
||||||
'kind=1&created_at>1740995200',
|
|
||||||
'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
content: 'Hello world',
|
|
||||||
sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6',
|
|
||||||
}),
|
|
||||||
).toEqual(null)
|
|
||||||
|
|
||||||
expect(
|
|
||||||
getDelegator({
|
|
||||||
id: 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc',
|
|
||||||
pubkey: '62903b1ff41559daf9ee98ef1ae67c152f301bb5ce26d14baba3052f649c3f49',
|
|
||||||
created_at: 1660896109,
|
|
||||||
kind: 1,
|
|
||||||
tags: [
|
|
||||||
[
|
|
||||||
'delegation',
|
|
||||||
'86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e',
|
|
||||||
'kind=1&created_at>1640995200',
|
|
||||||
'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
content: 'Hello world',
|
|
||||||
sig: 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6',
|
|
||||||
}),
|
|
||||||
).toEqual(null)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('create and verify delegation', async () => {
|
|
||||||
let sk1 = generatePrivateKey()
|
|
||||||
let pk1 = getPublicKey(sk1)
|
|
||||||
let sk2 = generatePrivateKey()
|
|
||||||
let pk2 = getPublicKey(sk2)
|
|
||||||
let delegation = createDelegation(sk1, { pubkey: pk2, kind: 1 })
|
|
||||||
expect(delegation).toHaveProperty('from', pk1)
|
|
||||||
expect(delegation).toHaveProperty('to', pk2)
|
|
||||||
expect(delegation).toHaveProperty('cond', 'kind=1')
|
|
||||||
|
|
||||||
let event = buildEvent({
|
|
||||||
kind: 1,
|
|
||||||
tags: [['delegation', delegation.from, delegation.cond, delegation.sig]],
|
|
||||||
pubkey: pk2,
|
|
||||||
})
|
|
||||||
expect(getDelegator(event)).toEqual(pk1)
|
|
||||||
})
|
|
||||||
71
nip26.ts
71
nip26.ts
@@ -1,71 +0,0 @@
|
|||||||
import { schnorr } from '@noble/curves/secp256k1'
|
|
||||||
import { bytesToHex } from '@noble/hashes/utils'
|
|
||||||
import { sha256 } from '@noble/hashes/sha256'
|
|
||||||
|
|
||||||
import { utf8Encoder } from './utils.ts'
|
|
||||||
import { getPublicKey } from './keys.ts'
|
|
||||||
|
|
||||||
import type { Event } from './event.ts'
|
|
||||||
|
|
||||||
export type Parameters = {
|
|
||||||
pubkey: string // the key to whom the delegation will be given
|
|
||||||
kind?: number
|
|
||||||
until?: number // delegation will only be valid until this date
|
|
||||||
since?: number // delegation will be valid from this date on
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Delegation = {
|
|
||||||
from: string // the pubkey who signed the delegation
|
|
||||||
to: string // the pubkey that is allowed to use the delegation
|
|
||||||
cond: string // the string of conditions as they should be included in the event tag
|
|
||||||
sig: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createDelegation(privateKey: string, parameters: Parameters): Delegation {
|
|
||||||
let conditions = []
|
|
||||||
if ((parameters.kind || -1) >= 0) conditions.push(`kind=${parameters.kind}`)
|
|
||||||
if (parameters.until) conditions.push(`created_at<${parameters.until}`)
|
|
||||||
if (parameters.since) conditions.push(`created_at>${parameters.since}`)
|
|
||||||
let cond = conditions.join('&')
|
|
||||||
|
|
||||||
if (cond === '') throw new Error('refusing to create a delegation without any conditions')
|
|
||||||
|
|
||||||
let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`))
|
|
||||||
|
|
||||||
let sig = bytesToHex(schnorr.sign(sighash, privateKey))
|
|
||||||
|
|
||||||
return {
|
|
||||||
from: getPublicKey(privateKey),
|
|
||||||
to: parameters.pubkey,
|
|
||||||
cond,
|
|
||||||
sig,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDelegator(event: Event<number>): string | null {
|
|
||||||
// find delegation tag
|
|
||||||
let tag = event.tags.find(tag => tag[0] === 'delegation' && tag.length >= 4)
|
|
||||||
if (!tag) return null
|
|
||||||
|
|
||||||
let pubkey = tag[1]
|
|
||||||
let cond = tag[2]
|
|
||||||
let sig = tag[3]
|
|
||||||
|
|
||||||
// check conditions
|
|
||||||
let conditions = cond.split('&')
|
|
||||||
for (let i = 0; i < conditions.length; i++) {
|
|
||||||
let [key, operator, value] = conditions[i].split(/\b/)
|
|
||||||
|
|
||||||
// the supported conditions are just 'kind' and 'created_at' for now
|
|
||||||
if (key === 'kind' && operator === '=' && event.kind === parseInt(value)) continue
|
|
||||||
else if (key === 'created_at' && operator === '<' && event.created_at < parseInt(value)) continue
|
|
||||||
else if (key === 'created_at' && operator === '>' && event.created_at > parseInt(value)) continue
|
|
||||||
else return null // invalid condition
|
|
||||||
}
|
|
||||||
|
|
||||||
// check signature
|
|
||||||
let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`))
|
|
||||||
if (!schnorr.verify(sig, sighash, pubkey)) return null
|
|
||||||
|
|
||||||
return pubkey
|
|
||||||
}
|
|
||||||
@@ -94,11 +94,6 @@
|
|||||||
"require": "./lib/cjs/nip25.js",
|
"require": "./lib/cjs/nip25.js",
|
||||||
"types": "./lib/types/nip25.d.ts"
|
"types": "./lib/types/nip25.d.ts"
|
||||||
},
|
},
|
||||||
"./nip26": {
|
|
||||||
"import": "./lib/esm/nip26.js",
|
|
||||||
"require": "./lib/cjs/nip26.js",
|
|
||||||
"types": "./lib/types/nip26.d.ts"
|
|
||||||
},
|
|
||||||
"./nip27": {
|
"./nip27": {
|
||||||
"import": "./lib/esm/nip27.js",
|
"import": "./lib/esm/nip27.js",
|
||||||
"require": "./lib/cjs/nip27.js",
|
"require": "./lib/cjs/nip27.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user