autopass 3.2.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,19 +71,36 @@ 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
 
84
101
  Get the local writer key.
85
102
 
86
- #### `inv = await pass.createInvite()`
103
+ #### `inv = await pass.createInvite({ readOnly })`
87
104
 
88
105
  Get invite to add a writer.
89
106
 
@@ -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,14 +78,25 @@ class AutopassPairer extends ReadyResource {
70
78
 
71
79
  await this.pass.deleteInvite()
72
80
  }
81
+
82
+ const metadata = result.data ? c.decode(PUBLIC_INVITE_METADATA, result.data) : null
83
+
73
84
  this.swarm = null
74
85
  this.store = null
75
- if (this.onresolve) this._whenWritable()
86
+ if (this.onresolve && metadata && metadata.readOnly) {
87
+ this._whenReadable()
88
+ } else if (this.onresolve) {
89
+ this._whenWritable()
90
+ }
76
91
  this.candidate.close().catch(noop)
77
92
  }
78
93
  })
79
94
  }
80
95
 
96
+ _whenReadable() {
97
+ this.onresolve(this.pass)
98
+ }
99
+
81
100
  _whenWritable() {
82
101
  if (this.pass.base.writable) return
83
102
  const check = () => {
@@ -136,11 +155,13 @@ class Autopass extends ReadyResource {
136
155
  this.debug = !!opts.key
137
156
  // Register handlers for commands
138
157
  this.router.add('@autopass/remove-writer', async (data, context) => {
158
+ await context.view.delete('@autopass/writer', data)
139
159
  await context.base.removeWriter(data.key)
140
160
  })
141
161
 
142
162
  this.router.add('@autopass/add-writer', async (data, context) => {
143
- await context.base.addWriter(data.key)
163
+ await context.view.insert('@autopass/writer', data)
164
+ if (!data.readOnly) await context.base.addWriter(data.key)
144
165
  })
145
166
 
146
167
  this.router.add('@autopass/put', async (data, context) => {
@@ -238,14 +259,23 @@ class Autopass extends ReadyResource {
238
259
 
239
260
  async createInvite(opts) {
240
261
  if (this.opened === false) await this.ready()
262
+ const readOnly = opts?.readOnly ? true : false
241
263
  const existing = await this.base.view.findOne('@autopass/invite', {})
242
- if (existing) {
264
+
265
+ if (existing && existing.readOnly !== readOnly) {
266
+ await this.deleteInvite()
267
+ } else if (existing) {
243
268
  if (this.member) await this.member.flushed()
244
269
  return z32.encode(existing.invite)
245
270
  }
246
- const { id, invite, publicKey, expires } = BlindPairing.createInvite(this.base.key)
271
+ const { id, invite, publicKey, expires, additional } = BlindPairing.createInvite(
272
+ this.base.key,
273
+ {
274
+ data: c.encode(PUBLIC_INVITE_METADATA, { readOnly })
275
+ }
276
+ )
247
277
 
248
- const record = { id, invite, publicKey, expires }
278
+ const record = { id, invite, publicKey, expires, readOnly, additional }
249
279
  await this.base.append(encode('@autopass/add-invite', record))
250
280
  if (this.member) await this.member.flushed()
251
281
  return z32.encode(record.invite)
@@ -271,19 +301,25 @@ class Autopass extends ReadyResource {
271
301
  return { value: data.value, file: data.file }
272
302
  }
273
303
 
274
- async addWriter(key) {
275
- await this.base.append(
276
- encode('@autopass/add-writer', {
277
- key: b4a.isBuffer(key) ? key : b4a.from(key)
278
- })
279
- )
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))
280
316
  return true
281
317
  }
282
318
 
283
319
  async removeWriter(key) {
284
320
  await this.base.append(
285
321
  encode('@autopass/remove-writer', {
286
- key: b4a.isBuffer(key) ? key : b4a.from(key)
322
+ key: b4a.isBuffer(key) ? key : b4a.from(key, 'hex')
287
323
  })
288
324
  )
289
325
  }
@@ -313,11 +349,14 @@ class Autopass extends ReadyResource {
313
349
  if (inv === null || !b4a.equals(inv.id, id)) {
314
350
  return
315
351
  }
352
+ const readOnly = inv.readOnly
316
353
  candidate.open(inv.publicKey)
317
- await this.addWriter(candidate.userData)
354
+ const { key, name } = c.decode(INVITEE, candidate.userData)
355
+ await this.addWriter({ key, name, readOnly })
318
356
  candidate.confirm({
319
357
  key: this.base.key,
320
- encryptionKey: this.base.encryptionKey
358
+ encryptionKey: this.base.encryptionKey,
359
+ additional: inv.additional
321
360
  })
322
361
  await this.deleteInvite()
323
362
  }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "autopass",
3
- "version": "3.2.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,28 @@ 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({
87
+ name: 'additional-invite-data',
88
+ fields: [
89
+ { name: 'data', type: 'buffer', required: true },
90
+ { name: 'signature', type: 'buffer', required: true }
91
+ ]
92
+ })
93
+
94
+ pass.register({
66
95
  name: 'invite',
67
96
  compact: false,
68
97
  fields: [
@@ -85,11 +114,21 @@ template.register({
85
114
  name: 'expires',
86
115
  type: 'int',
87
116
  required: true
117
+ },
118
+ {
119
+ name: 'readOnly',
120
+ type: 'bool',
121
+ required: false
122
+ },
123
+ {
124
+ name: 'additional',
125
+ type: '@autopass/additional-invite-data',
126
+ required: false
88
127
  }
89
128
  ]
90
129
  })
91
130
 
92
- template.register({
131
+ pass.register({
93
132
  name: 'del-invite',
94
133
  compact: false,
95
134
  fields: [
@@ -100,7 +139,7 @@ template.register({
100
139
  }
101
140
  ]
102
141
  })
103
- template.register({
142
+ pass.register({
104
143
  name: 'del-mirror',
105
144
  compact: false,
106
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,6 +7,8 @@
7
7
  "namespace": "autopass",
8
8
  "id": 0,
9
9
  "type": 1,
10
+ "version": 1,
11
+ "versionField": null,
10
12
  "indexes": [],
11
13
  "schema": "@autopass/records",
12
14
  "derived": false,
@@ -18,6 +20,8 @@
18
20
  "namespace": "autopass",
19
21
  "id": 1,
20
22
  "type": 1,
23
+ "version": 1,
24
+ "versionField": null,
21
25
  "indexes": [],
22
26
  "schema": "@autopass/invite",
23
27
  "derived": false,
@@ -29,6 +33,8 @@
29
33
  "namespace": "autopass",
30
34
  "id": 2,
31
35
  "type": 1,
36
+ "version": 1,
37
+ "versionField": null,
32
38
  "indexes": [],
33
39
  "schema": "@autopass/mirrors",
34
40
  "derived": false,
@@ -40,6 +46,8 @@
40
46
  "namespace": "autopass",
41
47
  "id": 3,
42
48
  "type": 1,
49
+ "version": 1,
50
+ "versionField": null,
43
51
  "indexes": [],
44
52
  "schema": "@autopass/writer",
45
53
  "derived": false,
@@ -51,6 +59,8 @@
51
59
  "namespace": "autopass",
52
60
  "id": 4,
53
61
  "type": 1,
62
+ "version": 1,
63
+ "versionField": null,
54
64
  "indexes": [],
55
65
  "schema": "@autopass/delete",
56
66
  "derived": false,
@@ -62,6 +72,8 @@
62
72
  "namespace": "autopass",
63
73
  "id": 5,
64
74
  "type": 1,
75
+ "version": 1,
76
+ "versionField": null,
65
77
  "indexes": [],
66
78
  "schema": "@autopass/del-invite",
67
79
  "derived": false,
@@ -73,6 +85,8 @@
73
85
  "namespace": "autopass",
74
86
  "id": 6,
75
87
  "type": 1,
88
+ "version": 1,
89
+ "versionField": null,
76
90
  "indexes": [],
77
91
  "schema": "@autopass/del-mirror",
78
92
  "derived": false,