autopass 3.3.0 → 3.4.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
@@ -71,13 +71,30 @@ Add new entry
71
71
 
72
72
  Remove an entry.
73
73
 
74
+ #### `stream = pass.listWriters(query)`
75
+
76
+ List all writers, optionally takes a hyperdb query
77
+
78
+ #### `writer = await pass.getWriter(key)
79
+
80
+ Get a writer, object similar to the addWriter input.
81
+
74
82
  #### `await pass.removeWriter(writerKey)`
75
83
 
76
84
  Remove a writer explictly.
77
85
 
78
- #### `await pass.addWriter(writerKey)`
86
+ #### `await pass.addWriter(writer)`
79
87
 
80
88
  Add a writer explictly.
89
+ Writer should look like this
90
+
91
+ ```
92
+ {
93
+ key: otherSidesLocalWriterKey,
94
+ name: 'optional name for the writer',
95
+ readOnly: false // weather the person can write or only read
96
+ }
97
+ ```
81
98
 
82
99
  #### `pass.writerKey`
83
100
 
@@ -127,7 +144,7 @@ Fully close the pass instance.
127
144
 
128
145
  Suspend the swarm and discovery
129
146
 
130
- #### `await pass.resume`
147
+ #### `await pass.resume()`
131
148
 
132
149
  Resume the swarm is suspended
133
150
 
package/index.js CHANGED
@@ -12,6 +12,12 @@ const { Router, encode, decode } = require('./spec/hyperdispatch')
12
12
  const BlindPeering = require('blind-peering')
13
13
  const db = require('./spec/db/index.js')
14
14
  const enc = require('hypercore-id-encoding')
15
+ const c = require('compact-encoding')
16
+
17
+ const { getEncoding } = require('./spec/schema/index.js')
18
+
19
+ const PUBLIC_INVITE_METADATA = getEncoding('@autopass/public-invite-metadata')
20
+ const INVITEE = getEncoding('@autopass/invitee')
15
21
 
16
22
  class AutopassPairer extends ReadyResource {
17
23
  constructor(store, invite, opts = {}) {
@@ -29,6 +35,7 @@ class AutopassPairer extends ReadyResource {
29
35
  this.pass = null
30
36
  this.relayThrough = opts.relayThrough || null
31
37
  this.blindEncryption = opts.blindEncryption || null
38
+ this.name = opts.name || null
32
39
 
33
40
  this.ready().catch(noop)
34
41
  }
@@ -54,9 +61,10 @@ class AutopassPairer extends ReadyResource {
54
61
  await core.ready()
55
62
  const key = core.key
56
63
  await core.close()
64
+
57
65
  this.candidate = this.pairing.addCandidate({
58
66
  invite: z32.decode(this.invite),
59
- userData: key,
67
+ userData: c.encode(INVITEE, { key, name: this.name }),
60
68
  onadd: async (result) => {
61
69
  if (this.pass === null) {
62
70
  this.pass = new Autopass(this.store, {
@@ -70,10 +78,12 @@ class AutopassPairer extends ReadyResource {
70
78
 
71
79
  await this.pass.deleteInvite()
72
80
  }
73
- const readOnly = JSON.parse(result.data.toString()).readOnly
81
+
82
+ const metadata = result.data ? c.decode(PUBLIC_INVITE_METADATA, result.data) : null
83
+
74
84
  this.swarm = null
75
85
  this.store = null
76
- if (this.onresolve && readOnly) {
86
+ if (this.onresolve && metadata && metadata.readOnly) {
77
87
  this._whenReadable()
78
88
  } else if (this.onresolve) {
79
89
  this._whenWritable()
@@ -84,11 +94,7 @@ class AutopassPairer extends ReadyResource {
84
94
  }
85
95
 
86
96
  _whenReadable() {
87
- const check = () => {
88
- this.pass.base.off('update', check)
89
- this.onresolve(this.pass)
90
- }
91
- this.pass.base.on('update', check)
97
+ this.onresolve(this.pass)
92
98
  }
93
99
 
94
100
  _whenWritable() {
@@ -149,11 +155,13 @@ class Autopass extends ReadyResource {
149
155
  this.debug = !!opts.key
150
156
  // Register handlers for commands
151
157
  this.router.add('@autopass/remove-writer', async (data, context) => {
158
+ await context.view.delete('@autopass/writer', data)
152
159
  await context.base.removeWriter(data.key)
153
160
  })
154
161
 
155
162
  this.router.add('@autopass/add-writer', async (data, context) => {
156
- await context.base.addWriter(data.key)
163
+ await context.view.insert('@autopass/writer', data)
164
+ if (!data.readOnly) await context.base.addWriter(data.key)
157
165
  })
158
166
 
159
167
  this.router.add('@autopass/put', async (data, context) => {
@@ -263,7 +271,7 @@ class Autopass extends ReadyResource {
263
271
  const { id, invite, publicKey, expires, additional } = BlindPairing.createInvite(
264
272
  this.base.key,
265
273
  {
266
- data: Buffer.from(JSON.stringify({ readOnly }))
274
+ data: c.encode(PUBLIC_INVITE_METADATA, { readOnly })
267
275
  }
268
276
  )
269
277
 
@@ -293,19 +301,25 @@ class Autopass extends ReadyResource {
293
301
  return { value: data.value, file: data.file }
294
302
  }
295
303
 
296
- async addWriter(key) {
297
- await this.base.append(
298
- encode('@autopass/add-writer', {
299
- key: b4a.isBuffer(key) ? key : b4a.from(key)
300
- })
301
- )
304
+ listWriters(query) {
305
+ return this.base.view.find('@autopass/writer', query)
306
+ }
307
+
308
+ async getWriter(key) {
309
+ return this.base.view.get('@autopass/writer', { key })
310
+ }
311
+
312
+ async addWriter(data) {
313
+ if (typeof data === 'string') data = b4a.from(data, 'hex')
314
+ if (b4a.isBuffer(data)) data = { key: data, name: null, readOnly: false }
315
+ await this.base.append(encode('@autopass/add-writer', data))
302
316
  return true
303
317
  }
304
318
 
305
319
  async removeWriter(key) {
306
320
  await this.base.append(
307
321
  encode('@autopass/remove-writer', {
308
- key: b4a.isBuffer(key) ? key : b4a.from(key)
322
+ key: b4a.isBuffer(key) ? key : b4a.from(key, 'hex')
309
323
  })
310
324
  )
311
325
  }
@@ -337,9 +351,8 @@ class Autopass extends ReadyResource {
337
351
  }
338
352
  const readOnly = inv.readOnly
339
353
  candidate.open(inv.publicKey)
340
- if (!readOnly) {
341
- await this.addWriter(candidate.userData)
342
- }
354
+ const { key, name } = c.decode(INVITEE, candidate.userData)
355
+ await this.addWriter({ key, name, readOnly })
343
356
  candidate.confirm({
344
357
  key: this.base.key,
345
358
  encryptionKey: this.base.encryptionKey,
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "autopass",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
- "brittle": "npx brittle test.js",
7
- "lint": "npx prettier . --check",
6
+ "brittle": "brittle test.js",
7
+ "lint": "prettier . --check",
8
+ "format": "prettier . --write",
8
9
  "test": "npm run lint && npm run brittle"
9
10
  },
10
11
  "author": "Holepunch Inc",
package/schema.js CHANGED
@@ -4,9 +4,9 @@ const Hyperdispatch = require('hyperdispatch')
4
4
 
5
5
  // SCHEMA CREATION START //
6
6
  const autopass = Hyperschema.from('./spec/schema')
7
- const template = autopass.namespace('autopass')
7
+ const pass = autopass.namespace('autopass')
8
8
  // You can find a list of supported data types here: https://github.com/holepunchto/compact-encoding
9
- template.register({
9
+ pass.register({
10
10
  name: 'records',
11
11
  compact: false,
12
12
  fields: [
@@ -27,7 +27,7 @@ template.register({
27
27
  }
28
28
  ]
29
29
  })
30
- template.register({
30
+ pass.register({
31
31
  name: 'mirrors',
32
32
  compact: false,
33
33
  fields: [
@@ -38,7 +38,7 @@ template.register({
38
38
  }
39
39
  ]
40
40
  })
41
- template.register({
41
+ pass.register({
42
42
  name: 'writer',
43
43
  compact: false,
44
44
  fields: [
@@ -46,11 +46,19 @@ template.register({
46
46
  name: 'key',
47
47
  type: 'buffer',
48
48
  required: true
49
+ },
50
+ {
51
+ name: 'name',
52
+ type: 'string'
53
+ },
54
+ {
55
+ name: 'readOnly',
56
+ type: 'bool'
49
57
  }
50
58
  ]
51
59
  })
52
60
 
53
- template.register({
61
+ pass.register({
54
62
  name: 'delete',
55
63
  compact: false,
56
64
  fields: [
@@ -62,7 +70,20 @@ template.register({
62
70
  ]
63
71
  })
64
72
 
65
- template.register({
73
+ pass.register({
74
+ name: 'invitee',
75
+ fields: [
76
+ { name: 'key', type: 'fixed32', required: true },
77
+ { name: 'name', type: 'string' }
78
+ ]
79
+ })
80
+
81
+ pass.register({
82
+ name: 'public-invite-metadata',
83
+ fields: [{ name: 'readOnly', type: 'bool' }]
84
+ })
85
+
86
+ pass.register({
66
87
  name: 'additional-invite-data',
67
88
  fields: [
68
89
  { name: 'data', type: 'buffer', required: true },
@@ -70,7 +91,7 @@ template.register({
70
91
  ]
71
92
  })
72
93
 
73
- template.register({
94
+ pass.register({
74
95
  name: 'invite',
75
96
  compact: false,
76
97
  fields: [
@@ -97,7 +118,7 @@ template.register({
97
118
  {
98
119
  name: 'readOnly',
99
120
  type: 'bool',
100
- required: true
121
+ required: false
101
122
  },
102
123
  {
103
124
  name: 'additional',
@@ -107,7 +128,7 @@ template.register({
107
128
  ]
108
129
  })
109
130
 
110
- template.register({
131
+ pass.register({
111
132
  name: 'del-invite',
112
133
  compact: false,
113
134
  fields: [
@@ -118,7 +139,7 @@ template.register({
118
139
  }
119
140
  ]
120
141
  })
121
- template.register({
142
+ pass.register({
122
143
  name: 'del-mirror',
123
144
  compact: false,
124
145
  fields: [
package/spec/db/db.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": 0,
2
+ "version": 1,
3
3
  "offset": 0,
4
4
  "schema": [
5
5
  {
@@ -7,7 +7,7 @@
7
7
  "namespace": "autopass",
8
8
  "id": 0,
9
9
  "type": 1,
10
- "version": 0,
10
+ "version": 1,
11
11
  "versionField": null,
12
12
  "indexes": [],
13
13
  "schema": "@autopass/records",
@@ -20,7 +20,7 @@
20
20
  "namespace": "autopass",
21
21
  "id": 1,
22
22
  "type": 1,
23
- "version": 0,
23
+ "version": 1,
24
24
  "versionField": null,
25
25
  "indexes": [],
26
26
  "schema": "@autopass/invite",
@@ -33,7 +33,7 @@
33
33
  "namespace": "autopass",
34
34
  "id": 2,
35
35
  "type": 1,
36
- "version": 0,
36
+ "version": 1,
37
37
  "versionField": null,
38
38
  "indexes": [],
39
39
  "schema": "@autopass/mirrors",
@@ -46,7 +46,7 @@
46
46
  "namespace": "autopass",
47
47
  "id": 3,
48
48
  "type": 1,
49
- "version": 0,
49
+ "version": 1,
50
50
  "versionField": null,
51
51
  "indexes": [],
52
52
  "schema": "@autopass/writer",
@@ -59,7 +59,7 @@
59
59
  "namespace": "autopass",
60
60
  "id": 4,
61
61
  "type": 1,
62
- "version": 0,
62
+ "version": 1,
63
63
  "versionField": null,
64
64
  "indexes": [],
65
65
  "schema": "@autopass/delete",
@@ -72,7 +72,7 @@
72
72
  "namespace": "autopass",
73
73
  "id": 5,
74
74
  "type": 1,
75
- "version": 0,
75
+ "version": 1,
76
76
  "versionField": null,
77
77
  "indexes": [],
78
78
  "schema": "@autopass/del-invite",
@@ -85,7 +85,7 @@
85
85
  "namespace": "autopass",
86
86
  "id": 6,
87
87
  "type": 1,
88
- "version": 0,
88
+ "version": 1,
89
89
  "versionField": null,
90
90
  "indexes": [],
91
91
  "schema": "@autopass/del-mirror",
package/spec/db/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  const { IndexEncoder, c, b4a } = require('hyperdb/runtime')
5
5
  const { version, getEncoding, setVersion } = require('./messages.js')
6
6
 
7
- const versions = { schema: version, db: 0 }
7
+ const versions = { schema: version, db: 1 }
8
8
 
9
9
  // '@autopass/records' collection key
10
10
  const collection0_key = new IndexEncoder([IndexEncoder.STRING], { prefix: 0 })
@@ -22,6 +22,9 @@ function collection0_reconstruct(schemaVersion, keyBuf, valueBuf) {
22
22
  const key = collection0_key.decode(keyBuf)
23
23
  setVersion(schemaVersion)
24
24
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
25
+ const type = c.uint.decode(state)
26
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
27
+ collection0.decodedVersion = c.uint.decode(state)
25
28
  const record = collection0_enc.decode(state)
26
29
  record.key = key[0]
27
30
  return record
@@ -38,7 +41,7 @@ function collection0_reconstruct_key(keyBuf) {
38
41
  const collection0 = {
39
42
  name: '@autopass/records',
40
43
  id: 0,
41
- version: 0,
44
+ version: 1,
42
45
  encodeKey(record) {
43
46
  const key = [record.key]
44
47
  return collection0_key.encode(key)
@@ -53,9 +56,11 @@ const collection0 = {
53
56
  },
54
57
  encodeValue(schemaVersion, collectionVersion, record) {
55
58
  setVersion(schemaVersion)
56
- const state = { start: 0, end: 0, buffer: null }
59
+ const state = { start: 0, end: 2, buffer: null }
57
60
  collection0_enc.preencode(state, record)
58
61
  state.buffer = b4a.allocUnsafe(state.end)
62
+ state.buffer[state.start++] = 0
63
+ state.buffer[state.start++] = collectionVersion
59
64
  collection0_enc.encode(state, record)
60
65
  return state.buffer
61
66
  },
@@ -82,6 +87,9 @@ function collection1_reconstruct(schemaVersion, keyBuf, valueBuf) {
82
87
  const key = collection1_key.decode(keyBuf)
83
88
  setVersion(schemaVersion)
84
89
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
90
+ const type = c.uint.decode(state)
91
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
92
+ collection1.decodedVersion = c.uint.decode(state)
85
93
  const record = collection1_enc.decode(state)
86
94
  record.id = key[0]
87
95
  return record
@@ -98,7 +106,7 @@ function collection1_reconstruct_key(keyBuf) {
98
106
  const collection1 = {
99
107
  name: '@autopass/invite',
100
108
  id: 1,
101
- version: 0,
109
+ version: 1,
102
110
  encodeKey(record) {
103
111
  const key = [record.id]
104
112
  return collection1_key.encode(key)
@@ -113,9 +121,11 @@ const collection1 = {
113
121
  },
114
122
  encodeValue(schemaVersion, collectionVersion, record) {
115
123
  setVersion(schemaVersion)
116
- const state = { start: 0, end: 0, buffer: null }
124
+ const state = { start: 0, end: 2, buffer: null }
117
125
  collection1_enc.preencode(state, record)
118
126
  state.buffer = b4a.allocUnsafe(state.end)
127
+ state.buffer[state.start++] = 0
128
+ state.buffer[state.start++] = collectionVersion
119
129
  collection1_enc.encode(state, record)
120
130
  return state.buffer
121
131
  },
@@ -142,6 +152,9 @@ function collection2_reconstruct(schemaVersion, keyBuf, valueBuf) {
142
152
  const key = collection2_key.decode(keyBuf)
143
153
  setVersion(schemaVersion)
144
154
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
155
+ const type = c.uint.decode(state)
156
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
157
+ collection2.decodedVersion = c.uint.decode(state)
145
158
  const record = collection2_enc.decode(state)
146
159
  record.key = key[0]
147
160
  return record
@@ -158,7 +171,7 @@ function collection2_reconstruct_key(keyBuf) {
158
171
  const collection2 = {
159
172
  name: '@autopass/mirrors',
160
173
  id: 2,
161
- version: 0,
174
+ version: 1,
162
175
  encodeKey(record) {
163
176
  const key = [record.key]
164
177
  return collection2_key.encode(key)
@@ -173,9 +186,11 @@ const collection2 = {
173
186
  },
174
187
  encodeValue(schemaVersion, collectionVersion, record) {
175
188
  setVersion(schemaVersion)
176
- const state = { start: 0, end: 0, buffer: null }
189
+ const state = { start: 0, end: 2, buffer: null }
177
190
  collection2_enc.preencode(state, record)
178
191
  state.buffer = b4a.allocUnsafe(state.end)
192
+ state.buffer[state.start++] = 0
193
+ state.buffer[state.start++] = collectionVersion
179
194
  collection2_enc.encode(state, record)
180
195
  return state.buffer
181
196
  },
@@ -202,6 +217,9 @@ function collection3_reconstruct(schemaVersion, keyBuf, valueBuf) {
202
217
  const key = collection3_key.decode(keyBuf)
203
218
  setVersion(schemaVersion)
204
219
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
220
+ const type = c.uint.decode(state)
221
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
222
+ collection3.decodedVersion = c.uint.decode(state)
205
223
  const record = collection3_enc.decode(state)
206
224
  record.key = key[0]
207
225
  return record
@@ -218,7 +236,7 @@ function collection3_reconstruct_key(keyBuf) {
218
236
  const collection3 = {
219
237
  name: '@autopass/writer',
220
238
  id: 3,
221
- version: 0,
239
+ version: 1,
222
240
  encodeKey(record) {
223
241
  const key = [record.key]
224
242
  return collection3_key.encode(key)
@@ -233,9 +251,11 @@ const collection3 = {
233
251
  },
234
252
  encodeValue(schemaVersion, collectionVersion, record) {
235
253
  setVersion(schemaVersion)
236
- const state = { start: 0, end: 0, buffer: null }
254
+ const state = { start: 0, end: 2, buffer: null }
237
255
  collection3_enc.preencode(state, record)
238
256
  state.buffer = b4a.allocUnsafe(state.end)
257
+ state.buffer[state.start++] = 0
258
+ state.buffer[state.start++] = collectionVersion
239
259
  collection3_enc.encode(state, record)
240
260
  return state.buffer
241
261
  },
@@ -262,6 +282,9 @@ function collection4_reconstruct(schemaVersion, keyBuf, valueBuf) {
262
282
  const key = collection4_key.decode(keyBuf)
263
283
  setVersion(schemaVersion)
264
284
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
285
+ const type = c.uint.decode(state)
286
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
287
+ collection4.decodedVersion = c.uint.decode(state)
265
288
  const record = collection4_enc.decode(state)
266
289
  record.key = key[0]
267
290
  return record
@@ -278,7 +301,7 @@ function collection4_reconstruct_key(keyBuf) {
278
301
  const collection4 = {
279
302
  name: '@autopass/delete',
280
303
  id: 4,
281
- version: 0,
304
+ version: 1,
282
305
  encodeKey(record) {
283
306
  const key = [record.key]
284
307
  return collection4_key.encode(key)
@@ -293,9 +316,11 @@ const collection4 = {
293
316
  },
294
317
  encodeValue(schemaVersion, collectionVersion, record) {
295
318
  setVersion(schemaVersion)
296
- const state = { start: 0, end: 0, buffer: null }
319
+ const state = { start: 0, end: 2, buffer: null }
297
320
  collection4_enc.preencode(state, record)
298
321
  state.buffer = b4a.allocUnsafe(state.end)
322
+ state.buffer[state.start++] = 0
323
+ state.buffer[state.start++] = collectionVersion
299
324
  collection4_enc.encode(state, record)
300
325
  return state.buffer
301
326
  },
@@ -322,6 +347,9 @@ function collection5_reconstruct(schemaVersion, keyBuf, valueBuf) {
322
347
  const key = collection5_key.decode(keyBuf)
323
348
  setVersion(schemaVersion)
324
349
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
350
+ const type = c.uint.decode(state)
351
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
352
+ collection5.decodedVersion = c.uint.decode(state)
325
353
  const record = collection5_enc.decode(state)
326
354
  record.id = key[0]
327
355
  return record
@@ -338,7 +366,7 @@ function collection5_reconstruct_key(keyBuf) {
338
366
  const collection5 = {
339
367
  name: '@autopass/del-invite',
340
368
  id: 5,
341
- version: 0,
369
+ version: 1,
342
370
  encodeKey(record) {
343
371
  const key = [record.id]
344
372
  return collection5_key.encode(key)
@@ -353,9 +381,11 @@ const collection5 = {
353
381
  },
354
382
  encodeValue(schemaVersion, collectionVersion, record) {
355
383
  setVersion(schemaVersion)
356
- const state = { start: 0, end: 0, buffer: null }
384
+ const state = { start: 0, end: 2, buffer: null }
357
385
  collection5_enc.preencode(state, record)
358
386
  state.buffer = b4a.allocUnsafe(state.end)
387
+ state.buffer[state.start++] = 0
388
+ state.buffer[state.start++] = collectionVersion
359
389
  collection5_enc.encode(state, record)
360
390
  return state.buffer
361
391
  },
@@ -382,6 +412,9 @@ function collection6_reconstruct(schemaVersion, keyBuf, valueBuf) {
382
412
  const key = collection6_key.decode(keyBuf)
383
413
  setVersion(schemaVersion)
384
414
  const state = { start: 0, end: valueBuf.byteLength, buffer: valueBuf }
415
+ const type = c.uint.decode(state)
416
+ if (type !== 0) throw new Error('Unknown collection type: ' + type)
417
+ collection6.decodedVersion = c.uint.decode(state)
385
418
  const record = collection6_enc.decode(state)
386
419
  record.key = key[0]
387
420
  return record
@@ -398,7 +431,7 @@ function collection6_reconstruct_key(keyBuf) {
398
431
  const collection6 = {
399
432
  name: '@autopass/del-mirror',
400
433
  id: 6,
401
- version: 0,
434
+ version: 1,
402
435
  encodeKey(record) {
403
436
  const key = [record.key]
404
437
  return collection6_key.encode(key)
@@ -413,9 +446,11 @@ const collection6 = {
413
446
  },
414
447
  encodeValue(schemaVersion, collectionVersion, record) {
415
448
  setVersion(schemaVersion)
416
- const state = { start: 0, end: 0, buffer: null }
449
+ const state = { start: 0, end: 2, buffer: null }
417
450
  collection6_enc.preencode(state, record)
418
451
  state.buffer = b4a.allocUnsafe(state.end)
452
+ state.buffer[state.start++] = 0
453
+ state.buffer[state.start++] = collectionVersion
419
454
  collection6_enc.encode(state, record)
420
455
  return state.buffer
421
456
  },