pairnet 0.2.0 → 0.2.2

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/index.js CHANGED
@@ -33,6 +33,7 @@ const requireEither = require("@validatem/require-either");
33
33
  const either = require("@validatem/either");
34
34
  const arrayOf = require("@validatem/array-of");
35
35
  const allowExtraProperties = require("@validatem/allow-extra-properties");
36
+ const isPlainObject = require("@validatem/is-plain-object");
36
37
  const isFunction = require("@validatem/is-function");
37
38
  const isBuffer = require("@validatem/is-buffer");
38
39
  const isBoolean = require("@validatem/is-boolean");
@@ -143,12 +144,11 @@ module.exports = {
143
144
  };
144
145
  }
145
146
 
146
- async function makeRawPairingToken() {
147
+ async function makeRawPairingToken(data) {
147
148
  let token = generatePairingToken();
148
149
  // TODO: Expiry
149
- // TODO: Allow data to be associated with the token?
150
- await store.setValidPairingToken(token);
151
- debug(`[generatePairingToken] Generated pairing token ${token}`);
150
+ await store.setValidPairingToken(token, data ?? {});
151
+ debug(`[generatePairingToken] Generated pairing token ${token}`); // TODO: log associated data?
152
152
  return token;
153
153
  }
154
154
 
@@ -246,11 +246,21 @@ module.exports = {
246
246
 
247
247
  return {
248
248
  fingerprint: identity.fingerprint,
249
+ getPeerData: async function (fingerprint) {
250
+ let storedData = await store.getPeerData(fingerprint);
251
+
252
+ if (storedData === NotSet) {
253
+ throw new Error(`Specified fingerprint is not known, cannot retrieve peer data`);
254
+ } else {
255
+ return storedData;
256
+ }
257
+ },
249
258
  generatePairingToken: async function (_port, _options) {
250
- let [ port, { compact }] = validateArguments(arguments, {
259
+ let [ port, { compact, data }] = validateArguments(arguments, {
251
260
  port: [ required, isPortNumber ],
252
261
  options: [ defaultTo({}), {
253
- compact: [ defaultTo(false), isBoolean ]
262
+ compact: [ defaultTo(false), isBoolean ],
263
+ data: [ defaultTo({}), isPlainObject ],
254
264
  }]
255
265
  });
256
266
 
@@ -261,7 +271,7 @@ module.exports = {
261
271
  ? reduceAddresses(ips.all)
262
272
  : ips.all,
263
273
  port: port,
264
- rawToken: await makeRawPairingToken(),
274
+ rawToken: await makeRawPairingToken(data),
265
275
  fingerprint: identity.fingerprint,
266
276
  });
267
277
  },
@@ -314,12 +324,13 @@ module.exports = {
314
324
  });
315
325
  },
316
326
  createServer: async function (_option) {
317
- let { hostname, port, onConnect, onDisconnect, onQuery } = validateOptions(arguments, {
327
+ let { hostname, port, onConnect, onDisconnect, onQuery, onPaired } = validateOptions(arguments, {
318
328
  hostname: [ isNonEmptyString ], /* undefined == listen on all public interfaces */
319
329
  port: [ required, isPortNumber ],
320
330
  onConnect: [ required, isFunction ],
321
331
  onDisconnect: [ isFunction ],
322
- onQuery: [ required, isFunction ]
332
+ onQuery: [ required, isFunction ],
333
+ onPaired: [ isFunction ]
323
334
  });
324
335
 
325
336
  if (protocolConfiguration.isServer) {
@@ -358,8 +369,10 @@ module.exports = {
358
369
  let { token } = query;
359
370
 
360
371
  if (await store.isValidPairingToken(token) === true) {
361
- await store.trustPeer(clientFingerprint, { /* FIXME */ });
362
- await store.removeValidPairingToken(token);
372
+ // TODO: What happens if a client chooses to remain connected after pairing? Can this possibility result in any security issues?
373
+ let data = await store.removeValidPairingToken(token);
374
+ await store.trustPeer(clientFingerprint, { data });
375
+ await onPaired?.(clientFingerprint);
363
376
  return true;
364
377
  } else {
365
378
  // TODO: Force disconnect?
@@ -29,7 +29,7 @@ module.exports = async function createFileStorage(folder) {
29
29
  },
30
30
  get: async function (key) {
31
31
  try {
32
- return fs.readFile(path.join(folder, safeName(key)));
32
+ return await fs.readFile(path.join(folder, safeName(key)));
33
33
  } catch (error) {
34
34
  if (error.code === "ENOENT") {
35
35
  return NotSet;
package/lib/store.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ const assert = require("node:assert");
3
4
  const { NotSet } = require("./storages/symbols");
4
5
 
5
6
  module.exports = function (storage) {
@@ -12,13 +13,17 @@ module.exports = function (storage) {
12
13
  return storage.set("pairnet_identity", identity);
13
14
  },
14
15
  isValidPairingToken: async function (token) {
15
- return (await storage.get(`pairnet_token_${token.toString("hex")}`) === true);
16
+ return (await storage.get(`pairnet_token_${token.toString("hex")}`) !== NotSet);
16
17
  },
17
- setValidPairingToken: async function (token) {
18
- return storage.set(`pairnet_token_${token.toString("hex")}`, true);
18
+ setValidPairingToken: async function (token, data) {
19
+ assert(data != null);
20
+ return storage.set(`pairnet_token_${token.toString("hex")}`, data);
19
21
  },
20
22
  removeValidPairingToken: async function (token) {
21
- return storage.delete(`pairnet_token_${token.toString("hex")}`);
23
+ let key = `pairnet_token_${token.toString("hex")}`;
24
+ let data = storage.get(key);
25
+ await storage.delete(key);
26
+ return data;
22
27
  },
23
28
  trustPeer: async function (fingerprint, data) {
24
29
  return storage.set(`pairnet_peer_${fingerprint}`, data ?? {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pairnet",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "keywords": [],
@@ -27,6 +27,7 @@
27
27
  "@validatem/is-buffer": "^0.1.1",
28
28
  "@validatem/is-function": "^0.1.0",
29
29
  "@validatem/is-non-empty-string": "^0.1.1",
30
+ "@validatem/is-plain-object": "^0.1.1",
30
31
  "@validatem/is-port-number": "^1.0.0",
31
32
  "@validatem/require-either": "^0.1.0",
32
33
  "@validatem/required": "^0.1.1",
package/test/index.js CHANGED
@@ -51,17 +51,21 @@ async function makePeer(overrides) {
51
51
  test("full procedure", async (t) => {
52
52
  let peer1 = await makePeer();
53
53
  let peer2 = await makePeer();
54
+ let pairedFingerprint;
54
55
 
55
56
  let server = await peer1.createServer({
56
57
  hostname: "localhost", port: 4005,
57
58
  onQuery: (fingerprint, query) => ({ number: query.number * 2, hasFingerprint: (fingerprint != null) }),
58
59
  onConnect: async (peer) => {
59
60
  yeetStream(peer.eventStream);
61
+ },
62
+ onPaired: async (fingerprint) => {
63
+ pairedFingerprint = fingerprint;
60
64
  }
61
65
  });
62
66
 
63
67
  // let token = await peer1.generatePairingToken(4005);
64
- let rawToken = await peer1.generateRawPairingToken();
68
+ let rawToken = await peer1.generateRawPairingToken({ foo: "bar" });
65
69
 
66
70
  await t.test("fails on wrong fingerprint", { timeout: 500 }, async () => {
67
71
  await assert.rejects(async () => {
@@ -85,6 +89,9 @@ test("full procedure", async (t) => {
85
89
  await peer.disconnect();
86
90
  // FIXME: Test query error reply
87
91
  });
92
+
93
+ assert.strictEqual(pairedFingerprint, peer2.fingerprint);
94
+ assert.deepStrictEqual(await peer1.getPeerData(peer2.fingerprint), { data: { foo: "bar" }});
88
95
  });
89
96
 
90
97
  await server.stop();
@@ -105,8 +112,9 @@ test("full procedure with wrapped token", async (t) => {
105
112
  let fingerprint;
106
113
 
107
114
  await t.test("pair", { timeout: 500 }, async () => {
108
- let token = await peer1.generatePairingToken(4005);
115
+ let token = await peer1.generatePairingToken(4005, { data: { foo: "bar" }});
109
116
  fingerprint = await peer2.pair(token);
117
+ assert.deepStrictEqual(await peer1.getPeerData(peer2.fingerprint), { data: { foo: "bar" }});
110
118
  });
111
119
 
112
120
  await t.test("connect", { timeout: 500 }, async () => {