nostr-double-ratchet 0.0.25 → 0.0.27

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/src/Session.ts CHANGED
@@ -46,29 +46,54 @@ export class Session {
46
46
  * @param name Optional name for the session (for debugging)
47
47
  * @returns A new Session instance
48
48
  */
49
- static init(nostrSubscribe: NostrSubscribe, theirNextNostrPublicKey: string, ourCurrentPrivateKey: Uint8Array, isInitiator: boolean, sharedSecret: Uint8Array, name?: string): Session {
49
+ static init(
50
+ nostrSubscribe: NostrSubscribe,
51
+ theirEphemeralNostrPublicKey: string,
52
+ ourEphemeralNostrPrivateKey: Uint8Array,
53
+ isInitiator: boolean,
54
+ sharedSecret: Uint8Array,
55
+ name?: string
56
+ ): Session {
50
57
  const ourNextPrivateKey = generateSecretKey();
51
- const [rootKey, sendingChainKey] = kdf(sharedSecret, nip44.getConversationKey(ourNextPrivateKey, theirNextNostrPublicKey), 2);
52
- let ourCurrentNostrKey;
53
- let ourNextNostrKey;
58
+
59
+ let rootKey: Uint8Array;
60
+ let sendingChainKey: Uint8Array | undefined;
61
+ let ourCurrentNostrKey: { publicKey: string, privateKey: Uint8Array } | undefined;
62
+ let ourNextNostrKey: { publicKey: string, privateKey: Uint8Array };
63
+
54
64
  if (isInitiator) {
55
- ourCurrentNostrKey = { publicKey: getPublicKey(ourCurrentPrivateKey), privateKey: ourCurrentPrivateKey };
56
- ourNextNostrKey = { publicKey: getPublicKey(ourNextPrivateKey), privateKey: ourNextPrivateKey };
65
+ [rootKey, sendingChainKey] = kdf(sharedSecret, nip44.getConversationKey(ourNextPrivateKey, theirEphemeralNostrPublicKey), 2);
66
+ ourCurrentNostrKey = {
67
+ publicKey: getPublicKey(ourEphemeralNostrPrivateKey),
68
+ privateKey: ourEphemeralNostrPrivateKey
69
+ };
70
+ ourNextNostrKey = {
71
+ publicKey: getPublicKey(ourNextPrivateKey),
72
+ privateKey: ourNextPrivateKey
73
+ };
57
74
  } else {
58
- ourNextNostrKey = { publicKey: getPublicKey(ourCurrentPrivateKey), privateKey: ourCurrentPrivateKey };
75
+ rootKey = sharedSecret;
76
+ sendingChainKey = undefined;
77
+ ourCurrentNostrKey = undefined;
78
+ ourNextNostrKey = {
79
+ publicKey: getPublicKey(ourEphemeralNostrPrivateKey),
80
+ privateKey: ourEphemeralNostrPrivateKey
81
+ };
59
82
  }
83
+
60
84
  const state: SessionState = {
61
- rootKey: isInitiator ? rootKey : sharedSecret,
62
- theirNextNostrPublicKey,
85
+ rootKey,
86
+ theirNextNostrPublicKey: theirEphemeralNostrPublicKey,
63
87
  ourCurrentNostrKey,
64
88
  ourNextNostrKey,
65
89
  receivingChainKey: undefined,
66
- sendingChainKey: isInitiator ? sendingChainKey : undefined,
90
+ sendingChainKey,
67
91
  sendingChainMessageNumber: 0,
68
92
  receivingChainMessageNumber: 0,
69
93
  previousSendingChainMessageCount: 0,
70
94
  skippedKeys: {},
71
95
  };
96
+
72
97
  const session = new Session(nostrSubscribe, state);
73
98
  if (name) session.name = name;
74
99
  return session;
@@ -193,11 +218,10 @@ export class Session {
193
218
  }
194
219
  }
195
220
 
196
- private ratchetStep(theirNextNostrPublicKey: string) {
221
+ private ratchetStep() {
197
222
  this.state.previousSendingChainMessageCount = this.state.sendingChainMessageNumber;
198
223
  this.state.sendingChainMessageNumber = 0;
199
224
  this.state.receivingChainMessageNumber = 0;
200
- this.state.theirNextNostrPublicKey = theirNextNostrPublicKey;
201
225
 
202
226
  const conversationKey1 = nip44.getConversationKey(this.state.ourNextNostrKey.privateKey, this.state.theirNextNostrPublicKey!);
203
227
  const [theirRootKey, receivingChainKey] = kdf(this.state.rootKey, conversationKey1, 2);
@@ -219,7 +243,9 @@ export class Session {
219
243
 
220
244
  // 3. MESSAGE KEY FUNCTIONS
221
245
  private skipMessageKeys(until: number, nostrSender: string) {
222
- if (this.state.receivingChainMessageNumber + MAX_SKIP < until) {
246
+ if (until <= this.state.receivingChainMessageNumber) return
247
+
248
+ if (until > this.state.receivingChainMessageNumber + MAX_SKIP) {
223
249
  throw new Error("Too many skipped messages");
224
250
  }
225
251
 
@@ -232,10 +258,14 @@ export class Session {
232
258
  // Store header keys
233
259
  if (this.state.ourCurrentNostrKey) {
234
260
  const currentSecret = nip44.getConversationKey(this.state.ourCurrentNostrKey.privateKey, nostrSender);
235
- this.state.skippedKeys[nostrSender].headerKeys.push(currentSecret);
261
+ if (!this.state.skippedKeys[nostrSender].headerKeys.includes(currentSecret)) {
262
+ this.state.skippedKeys[nostrSender].headerKeys.push(currentSecret);
263
+ }
236
264
  }
237
265
  const nextSecret = nip44.getConversationKey(this.state.ourNextNostrKey.privateKey, nostrSender);
238
- this.state.skippedKeys[nostrSender].headerKeys.push(nextSecret);
266
+ if (!this.state.skippedKeys[nostrSender].headerKeys.includes(nextSecret)) {
267
+ this.state.skippedKeys[nostrSender].headerKeys.push(nextSecret);
268
+ }
239
269
  }
240
270
 
241
271
  while (this.state.receivingChainMessageNumber < until) {
@@ -316,7 +346,7 @@ export class Session {
316
346
 
317
347
  if (shouldRatchet) {
318
348
  this.skipMessageKeys(header.previousChainLength, e.pubkey);
319
- this.ratchetStep(header.nextPublicKey);
349
+ this.ratchetStep();
320
350
  }
321
351
  } else {
322
352
  if (!this.state.skippedKeys[e.pubkey]?.messageKeys[header.number]) {
package/src/types.ts CHANGED
@@ -66,6 +66,9 @@ export type Unsubscribe = () => void;
66
66
  * Function that subscribes to Nostr events matching a filter and calls onEvent for each event.
67
67
  */
68
68
  export type NostrSubscribe = (filter: Filter, onEvent: (e: VerifiedEvent) => void) => Unsubscribe;
69
+ export type EncryptFunction = (plaintext: string, pubkey: string) => Promise<string>;
70
+ export type DecryptFunction = (ciphertext: string, pubkey: string) => Promise<string>;
71
+ export type NostrPublish = (event: UnsignedEvent) => Promise<VerifiedEvent>;
69
72
 
70
73
  export type Rumor = UnsignedEvent & { id: string }
71
74
 
@@ -100,7 +103,3 @@ export type NostrEvent = {
100
103
  content: string;
101
104
  sig: string;
102
105
  }
103
-
104
- export type EncryptFunction = (plaintext: string, pubkey: string) => Promise<string>;
105
- export type DecryptFunction = (ciphertext: string, pubkey: string) => Promise<string>;
106
- export type NostrPublish = (event: UnsignedEvent) => Promise<VerifiedEvent>;