nostr-tools 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,13 @@ Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
4
4
 
5
5
  Only depends on _@scure_ and _@noble_ packages.
6
6
 
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install nostr-tools # or yarn add nostr-tools
11
+ ```
12
+
13
+
7
14
  ## Usage
8
15
 
9
16
  ### Generating a private key and a public key
@@ -53,8 +60,6 @@ import {
53
60
  } from 'nostr-tools'
54
61
 
55
62
  const relay = relayInit('wss://relay.example.com')
56
- await relay.connect()
57
-
58
63
  relay.on('connect', () => {
59
64
  console.log(`connected to ${relay.url}`)
60
65
  })
@@ -62,6 +67,8 @@ relay.on('error', () => {
62
67
  console.log(`failed to connect to ${relay.url}`)
63
68
  })
64
69
 
70
+ await relay.connect()
71
+
65
72
  // let's query for an event that exists
66
73
  let sub = relay.sub([
67
74
  {
package/event.ts CHANGED
@@ -2,6 +2,7 @@ import * as secp256k1 from '@noble/secp256k1'
2
2
  import {sha256} from '@noble/hashes/sha256'
3
3
 
4
4
  import {utf8Encoder} from './utils'
5
+ import {getPublicKey} from './keys'
5
6
 
6
7
  /* eslint-disable no-unused-vars */
7
8
  export enum Kind {
@@ -32,8 +33,11 @@ export type EventTemplate = {
32
33
  created_at: number
33
34
  }
34
35
 
35
- export type Event = EventTemplate & {
36
+ export type UnsignedEvent = EventTemplate & {
36
37
  pubkey: string
38
+ }
39
+
40
+ export type Event = UnsignedEvent & {
37
41
  id: string
38
42
  sig: string
39
43
  }
@@ -47,7 +51,15 @@ export function getBlankEvent(): EventTemplate {
47
51
  }
48
52
  }
49
53
 
50
- export function serializeEvent(evt: Event): string {
54
+ export function finishEvent(t: EventTemplate, privateKey: string): Event {
55
+ let event = t as Event
56
+ event.pubkey = getPublicKey(privateKey)
57
+ event.id = getEventHash(event)
58
+ event.sig = signEvent(event, privateKey)
59
+ return event
60
+ }
61
+
62
+ export function serializeEvent(evt: UnsignedEvent): string {
51
63
  if (!validateEvent(evt))
52
64
  throw new Error("can't serialize event with wrong or missing properties")
53
65
 
@@ -61,12 +73,12 @@ export function serializeEvent(evt: Event): string {
61
73
  ])
62
74
  }
63
75
 
64
- export function getEventHash(event: Event): string {
76
+ export function getEventHash(event: UnsignedEvent): string {
65
77
  let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))
66
78
  return secp256k1.utils.bytesToHex(eventHash)
67
79
  }
68
80
 
69
- export function validateEvent(event: Event): boolean {
81
+ export function validateEvent(event: UnsignedEvent): boolean {
70
82
  if (typeof event !== 'object') return false
71
83
  if (typeof event.content !== 'string') return false
72
84
  if (typeof event.created_at !== 'number') return false
@@ -93,7 +105,7 @@ export function verifySignature(event: Event & {sig: string}): boolean {
93
105
  )
94
106
  }
95
107
 
96
- export function signEvent(event: Event, key: string): string {
108
+ export function signEvent(event: UnsignedEvent, key: string): string {
97
109
  return secp256k1.utils.bytesToHex(
98
110
  secp256k1.schnorr.signSync(getEventHash(event), key)
99
111
  )
@@ -3605,6 +3605,7 @@ zoo`.split("\n");
3605
3605
  __export(nostr_tools_exports, {
3606
3606
  Kind: () => Kind,
3607
3607
  SimplePool: () => SimplePool,
3608
+ finishEvent: () => finishEvent,
3608
3609
  fj: () => fakejson_exports,
3609
3610
  generatePrivateKey: () => generatePrivateKey,
3610
3611
  getBlankEvent: () => getBlankEvent,
@@ -5117,6 +5118,13 @@ zoo`.split("\n");
5117
5118
  created_at: 0
5118
5119
  };
5119
5120
  }
5121
+ function finishEvent(t, privateKey) {
5122
+ let event = t;
5123
+ event.pubkey = getPublicKey(privateKey);
5124
+ event.id = getEventHash(event);
5125
+ event.sig = signEvent(event, privateKey);
5126
+ return event;
5127
+ }
5120
5128
  function serializeEvent(evt) {
5121
5129
  if (!validateEvent(evt))
5122
5130
  throw new Error("can't serialize event with wrong or missing properties");
@@ -8459,7 +8467,8 @@ zoo`.split("\n");
8459
8467
  getZapEndpoint: () => getZapEndpoint,
8460
8468
  makeZapReceipt: () => makeZapReceipt,
8461
8469
  makeZapRequest: () => makeZapRequest,
8462
- useFetchImplementation: () => useFetchImplementation2
8470
+ useFetchImplementation: () => useFetchImplementation2,
8471
+ validateZapRequest: () => validateZapRequest
8463
8472
  });
8464
8473
  init_define_process();
8465
8474
  var _fetch2;
@@ -8500,13 +8509,17 @@ zoo`.split("\n");
8500
8509
  relays,
8501
8510
  comment = ""
8502
8511
  }) {
8512
+ if (!amount)
8513
+ throw new Error("amount not given");
8514
+ if (!profile)
8515
+ throw new Error("profile not given");
8503
8516
  let zr = {
8504
8517
  kind: 9734,
8505
8518
  created_at: Math.round(Date.now() / 1e3),
8506
8519
  content: comment,
8507
8520
  tags: [
8508
8521
  ["p", profile],
8509
- ["amount", amount],
8522
+ ["amount", amount.toString()],
8510
8523
  ["relays", ...relays]
8511
8524
  ]
8512
8525
  };
@@ -8515,6 +8528,30 @@ zoo`.split("\n");
8515
8528
  }
8516
8529
  return zr;
8517
8530
  }
8531
+ function validateZapRequest(zapRequestString) {
8532
+ let zapRequest;
8533
+ try {
8534
+ zapRequest = JSON.parse(zapRequestString);
8535
+ } catch (err) {
8536
+ return "Invalid zap request JSON.";
8537
+ }
8538
+ if (!validateEvent(zapRequest))
8539
+ return "Zap request is not a valid Nostr event.";
8540
+ if (!verifySignature(zapRequest))
8541
+ return "Invalid signature on zap request.";
8542
+ let p = zapRequest.tags.find(([t, v]) => t === "p" && v);
8543
+ if (!p)
8544
+ return "Zap request doesn't have a 'p' tag.";
8545
+ if (!p[1].match(/^[a-f0-9]{64}$/))
8546
+ return "Zap request 'p' tag is not valid hex.";
8547
+ let e = zapRequest.tags.find(([t, v]) => t === "e" && v);
8548
+ if (e && !e[1].match(/^[a-f0-9]{64}$/))
8549
+ return "Zap request 'e' tag is not valid hex.";
8550
+ let relays = zapRequest.tags.find(([t, v]) => t === "relays" && v);
8551
+ if (!relays)
8552
+ return "Zap request doesn't have a 'relays' tag.";
8553
+ return null;
8554
+ }
8518
8555
  function makeZapReceipt({
8519
8556
  zapRequest,
8520
8557
  preimage,