autopass 2.2.0 → 3.0.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/.gitattributes +1 -0
- package/.github/workflows/test-node.yml +7 -7
- package/.prettierrc +1 -0
- package/README.md +26 -15
- package/example.mjs +1 -1
- package/index.js +98 -44
- package/package.json +23 -19
- package/schema.js +108 -52
- package/spec/db/db.json +31 -19
- package/spec/db/index.js +197 -83
- package/spec/db/messages.js +127 -82
- package/spec/hyperdispatch/dispatch.json +16 -3
- package/spec/hyperdispatch/index.js +128 -38
- package/spec/hyperdispatch/messages.js +84 -44
- package/spec/schema/index.js +84 -44
- package/spec/schema/schema.json +31 -3
- package/test.js +58 -7
package/.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* text=auto eol=lf
|
|
@@ -14,10 +14,10 @@ jobs:
|
|
|
14
14
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
15
|
runs-on: ${{ matrix.os }}
|
|
16
16
|
steps:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
- uses: actions/checkout@v3
|
|
18
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
19
|
+
uses: actions/setup-node@v3
|
|
20
|
+
with:
|
|
21
|
+
node-version: ${{ matrix.node-version }}
|
|
22
|
+
- run: npm install
|
|
23
|
+
- run: npm test
|
package/.prettierrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"prettier-config-holepunch"
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Distributed notes/password manager
|
|
4
4
|
|
|
5
|
-
```
|
|
5
|
+
```sh
|
|
6
6
|
npm install autopass
|
|
7
7
|
```
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ npm install autopass
|
|
|
13
13
|
|
|
14
14
|
First choose if you wanna pair or make a new instance.
|
|
15
15
|
|
|
16
|
-
```
|
|
16
|
+
```js
|
|
17
17
|
import Autopass from 'autopass'
|
|
18
18
|
import Corestore from 'corestore'
|
|
19
19
|
|
|
@@ -25,7 +25,7 @@ console.log('share to add', inv)
|
|
|
25
25
|
|
|
26
26
|
Then invite another instance
|
|
27
27
|
|
|
28
|
-
```
|
|
28
|
+
```js
|
|
29
29
|
const pair = Autopass.pair(new Corestore('./another-pass'), inv)
|
|
30
30
|
|
|
31
31
|
const anotherPass = await pair.finished()
|
|
@@ -34,13 +34,13 @@ await anotherPass.ready()
|
|
|
34
34
|
|
|
35
35
|
When paired you can simply start the instance again with the normal constructor.
|
|
36
36
|
|
|
37
|
-
```
|
|
37
|
+
```js
|
|
38
38
|
await pass.add('a-note', 'hello this is a note')
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Then on the other node you get it out with
|
|
42
42
|
|
|
43
|
-
```
|
|
43
|
+
```js
|
|
44
44
|
const note = await pass.get('a-note')
|
|
45
45
|
console.log({ note })
|
|
46
46
|
```
|
|
@@ -59,23 +59,14 @@ Triggered when it updates, ie something added/removed an entry
|
|
|
59
59
|
|
|
60
60
|
Get an entry.
|
|
61
61
|
|
|
62
|
-
#### `value = await pass.getFile(name)`
|
|
63
|
-
|
|
64
|
-
Get a file.
|
|
65
|
-
|
|
66
62
|
#### `stream = pass.list()`
|
|
67
63
|
|
|
68
64
|
Get all entries.
|
|
69
65
|
|
|
70
|
-
#### `await pass.add(key, value)`
|
|
66
|
+
#### `await pass.add(key, value, file)`
|
|
71
67
|
|
|
72
68
|
Add new entry
|
|
73
69
|
|
|
74
|
-
#### `await pass.addFIle(name, buffer)`
|
|
75
|
-
|
|
76
|
-
Add new file
|
|
77
|
-
|
|
78
|
-
|
|
79
70
|
#### `await pass.remove(key)`
|
|
80
71
|
|
|
81
72
|
Remove an entry.
|
|
@@ -112,6 +103,18 @@ Pair with another instance.
|
|
|
112
103
|
|
|
113
104
|
Wait for the pair to finish.
|
|
114
105
|
|
|
106
|
+
#### `await pass.addMirror(key)`
|
|
107
|
+
|
|
108
|
+
Add a blind mirror.
|
|
109
|
+
|
|
110
|
+
#### `await getMirror()`
|
|
111
|
+
|
|
112
|
+
Returns an array of blind mirrors
|
|
113
|
+
|
|
114
|
+
#### `await removeMirror(key)`
|
|
115
|
+
|
|
116
|
+
Remove a blind mirror
|
|
117
|
+
|
|
115
118
|
#### `await pair.close()`
|
|
116
119
|
|
|
117
120
|
Force close the pair instance. Only need to call this if you dont wait for it to finish.get
|
|
@@ -120,6 +123,14 @@ Force close the pair instance. Only need to call this if you dont wait for it to
|
|
|
120
123
|
|
|
121
124
|
Fully close the pass instance.
|
|
122
125
|
|
|
126
|
+
#### `await pass.suspend()`
|
|
127
|
+
|
|
128
|
+
Suspend the swarm and discovery
|
|
129
|
+
|
|
130
|
+
#### `await pass.resume`
|
|
131
|
+
|
|
132
|
+
Resume the swarm is suspended
|
|
133
|
+
|
|
123
134
|
## Contributors
|
|
124
135
|
|
|
125
136
|
Written with big contributions from [@supersu](https://github.com/supersuryaansh)
|
package/example.mjs
CHANGED
package/index.js
CHANGED
|
@@ -7,16 +7,19 @@ const Hyperswarm = require('hyperswarm')
|
|
|
7
7
|
const ReadyResource = require('ready-resource')
|
|
8
8
|
const z32 = require('z32')
|
|
9
9
|
const b4a = require('b4a')
|
|
10
|
-
const { Router,
|
|
10
|
+
const { Router, encode, decode } = require('./spec/hyperdispatch')
|
|
11
|
+
const BlindPeering = require('blind-peering')
|
|
11
12
|
const db = require('./spec/db/index.js')
|
|
13
|
+
const enc = require('hypercore-id-encoding')
|
|
12
14
|
|
|
13
15
|
class AutopassPairer extends ReadyResource {
|
|
14
|
-
constructor
|
|
16
|
+
constructor(store, invite, opts = {}) {
|
|
15
17
|
super()
|
|
16
18
|
this.store = store
|
|
17
19
|
this.invite = invite
|
|
18
20
|
this.swarm = null
|
|
19
21
|
this.pairing = null
|
|
22
|
+
this.peering = null
|
|
20
23
|
this.candidate = null
|
|
21
24
|
this.bootstrap = opts.bootstrap || null
|
|
22
25
|
this.onresolve = null
|
|
@@ -26,7 +29,7 @@ class AutopassPairer extends ReadyResource {
|
|
|
26
29
|
this.ready().catch(noop)
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
async _open
|
|
32
|
+
async _open() {
|
|
30
33
|
await this.store.ready()
|
|
31
34
|
this.swarm = new Hyperswarm({
|
|
32
35
|
keyPair: await this.store.createKeyPair('hyperswarm'),
|
|
@@ -54,6 +57,8 @@ class AutopassPairer extends ReadyResource {
|
|
|
54
57
|
encryptionKey: result.encryptionKey,
|
|
55
58
|
bootstrap: this.bootstrap
|
|
56
59
|
})
|
|
60
|
+
|
|
61
|
+
await this.pass.deleteInvite()
|
|
57
62
|
}
|
|
58
63
|
this.swarm = null
|
|
59
64
|
this.store = null
|
|
@@ -63,7 +68,7 @@ class AutopassPairer extends ReadyResource {
|
|
|
63
68
|
})
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
_whenWritable
|
|
71
|
+
_whenWritable() {
|
|
67
72
|
if (this.pass.base.writable) return
|
|
68
73
|
const check = () => {
|
|
69
74
|
if (this.pass.base.writable) {
|
|
@@ -74,7 +79,7 @@ class AutopassPairer extends ReadyResource {
|
|
|
74
79
|
this.pass.base.on('update', check)
|
|
75
80
|
}
|
|
76
81
|
|
|
77
|
-
async _close
|
|
82
|
+
async _close() {
|
|
78
83
|
if (this.candidate !== null) {
|
|
79
84
|
await this.candidate.close()
|
|
80
85
|
}
|
|
@@ -94,7 +99,7 @@ class AutopassPairer extends ReadyResource {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
finished
|
|
102
|
+
finished() {
|
|
98
103
|
return new Promise((resolve, reject) => {
|
|
99
104
|
this.onresolve = resolve
|
|
100
105
|
this.onreject = reject
|
|
@@ -103,7 +108,7 @@ class AutopassPairer extends ReadyResource {
|
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
class Autopass extends ReadyResource {
|
|
106
|
-
constructor
|
|
111
|
+
constructor(corestore, opts = {}) {
|
|
107
112
|
super()
|
|
108
113
|
this.router = new Router()
|
|
109
114
|
this.store = corestore
|
|
@@ -127,10 +132,18 @@ class Autopass extends ReadyResource {
|
|
|
127
132
|
await context.view.insert('@autopass/records', data)
|
|
128
133
|
})
|
|
129
134
|
|
|
135
|
+
this.router.add('@autopass/add-mirror', async (data, context) => {
|
|
136
|
+
await context.view.insert('@autopass/mirrors', data)
|
|
137
|
+
})
|
|
138
|
+
|
|
130
139
|
this.router.add('@autopass/del', async (data, context) => {
|
|
131
140
|
await context.view.delete('@autopass/records', { key: data.key })
|
|
132
141
|
})
|
|
133
142
|
|
|
143
|
+
this.router.add('@autopass/del-mirror', async (data, context) => {
|
|
144
|
+
await context.view.delete('@autopass/mirrors', { key: data.key })
|
|
145
|
+
})
|
|
146
|
+
|
|
134
147
|
this.router.add('@autopass/add-invite', async (data, context) => {
|
|
135
148
|
await context.view.insert('@autopass/invite', data)
|
|
136
149
|
})
|
|
@@ -144,13 +157,13 @@ class Autopass extends ReadyResource {
|
|
|
144
157
|
}
|
|
145
158
|
|
|
146
159
|
// Initialize autobase
|
|
147
|
-
_boot
|
|
160
|
+
_boot(opts = {}) {
|
|
148
161
|
const { encryptionKey, key } = opts
|
|
149
162
|
|
|
150
163
|
this.base = new Autobase(this.store, key, {
|
|
151
164
|
encrypt: true,
|
|
152
165
|
encryptionKey,
|
|
153
|
-
open
|
|
166
|
+
open(store) {
|
|
154
167
|
return HyperDB.bee(store.get('view'), db, {
|
|
155
168
|
extension: false,
|
|
156
169
|
autoUpdate: true
|
|
@@ -165,19 +178,19 @@ class Autopass extends ReadyResource {
|
|
|
165
178
|
})
|
|
166
179
|
}
|
|
167
180
|
|
|
168
|
-
async _apply
|
|
181
|
+
async _apply(nodes, view, base) {
|
|
169
182
|
for (const node of nodes) {
|
|
170
183
|
await this.router.dispatch(node.value, { view, base })
|
|
171
184
|
}
|
|
172
185
|
await view.flush()
|
|
173
186
|
}
|
|
174
187
|
|
|
175
|
-
async _open
|
|
188
|
+
async _open() {
|
|
176
189
|
await this.base.ready()
|
|
177
190
|
if (this.replicate) await this._replicate()
|
|
178
191
|
}
|
|
179
192
|
|
|
180
|
-
async _close
|
|
193
|
+
async _close() {
|
|
181
194
|
if (this.swarm) {
|
|
182
195
|
await this.member.close()
|
|
183
196
|
await this.pairing.close()
|
|
@@ -186,73 +199,83 @@ class Autopass extends ReadyResource {
|
|
|
186
199
|
await this.base.close()
|
|
187
200
|
}
|
|
188
201
|
|
|
189
|
-
get writerKey
|
|
202
|
+
get writerKey() {
|
|
190
203
|
return this.base.local.key
|
|
191
204
|
}
|
|
192
205
|
|
|
193
|
-
get key
|
|
206
|
+
get key() {
|
|
194
207
|
return this.base.key
|
|
195
208
|
}
|
|
196
209
|
|
|
197
|
-
get discoveryKey
|
|
210
|
+
get discoveryKey() {
|
|
198
211
|
return this.base.discoveryKey
|
|
199
212
|
}
|
|
200
213
|
|
|
201
|
-
get encryptionKey
|
|
214
|
+
get encryptionKey() {
|
|
202
215
|
return this.base.encryptionKey
|
|
203
216
|
}
|
|
204
217
|
|
|
205
|
-
static pair
|
|
218
|
+
static pair(store, invite, opts) {
|
|
206
219
|
return new AutopassPairer(store, invite, opts)
|
|
207
220
|
}
|
|
208
221
|
|
|
209
|
-
async createInvite
|
|
222
|
+
async createInvite(opts) {
|
|
210
223
|
if (this.opened === false) await this.ready()
|
|
211
224
|
const existing = await this.base.view.findOne('@autopass/invite', {})
|
|
212
225
|
if (existing) {
|
|
213
226
|
return z32.encode(existing.invite)
|
|
214
227
|
}
|
|
215
|
-
const { id, invite, publicKey, expires } = BlindPairing.createInvite(
|
|
228
|
+
const { id, invite, publicKey, expires } = BlindPairing.createInvite(
|
|
229
|
+
this.base.key
|
|
230
|
+
)
|
|
216
231
|
|
|
217
232
|
const record = { id, invite, publicKey, expires }
|
|
218
|
-
await this.base.append(
|
|
233
|
+
await this.base.append(encode('@autopass/add-invite', record))
|
|
219
234
|
return z32.encode(record.invite)
|
|
220
235
|
}
|
|
221
236
|
|
|
222
|
-
async deleteInvite
|
|
237
|
+
async deleteInvite() {
|
|
223
238
|
if (this.opened === false) await this.ready()
|
|
224
239
|
const existing = await this.base.view.findOne('@autopass/invite', {})
|
|
225
240
|
if (existing) {
|
|
226
|
-
await this.base.append(
|
|
241
|
+
await this.base.append(encode('@autopass/del-invite', existing))
|
|
227
242
|
}
|
|
228
243
|
}
|
|
229
244
|
|
|
230
|
-
list
|
|
245
|
+
list(opts) {
|
|
231
246
|
return this.base.view.find('@autopass/records', {})
|
|
232
247
|
}
|
|
233
248
|
|
|
234
|
-
async get
|
|
249
|
+
async get(key) {
|
|
235
250
|
const data = await this.base.view.get('@autopass/records', { key })
|
|
236
251
|
if (data === null) {
|
|
237
252
|
return null
|
|
238
253
|
}
|
|
239
|
-
return data.value
|
|
254
|
+
return { value: data.value, file: data.file }
|
|
240
255
|
}
|
|
241
256
|
|
|
242
|
-
async addWriter
|
|
243
|
-
await this.base.append(
|
|
257
|
+
async addWriter(key) {
|
|
258
|
+
await this.base.append(
|
|
259
|
+
encode('@autopass/add-writer', {
|
|
260
|
+
key: b4a.isBuffer(key) ? key : b4a.from(key)
|
|
261
|
+
})
|
|
262
|
+
)
|
|
244
263
|
return true
|
|
245
264
|
}
|
|
246
265
|
|
|
247
|
-
async removeWriter
|
|
248
|
-
await this.base.append(
|
|
266
|
+
async removeWriter(key) {
|
|
267
|
+
await this.base.append(
|
|
268
|
+
encode('@autopass/remove-writer', {
|
|
269
|
+
key: b4a.isBuffer(key) ? key : b4a.from(key)
|
|
270
|
+
})
|
|
271
|
+
)
|
|
249
272
|
}
|
|
250
273
|
|
|
251
|
-
get writable
|
|
274
|
+
get writable() {
|
|
252
275
|
return this.base.writable
|
|
253
276
|
}
|
|
254
277
|
|
|
255
|
-
async _replicate
|
|
278
|
+
async _replicate() {
|
|
256
279
|
await this.base.ready()
|
|
257
280
|
if (this.swarm === null) {
|
|
258
281
|
this.swarm = new Hyperswarm({
|
|
@@ -269,7 +292,7 @@ class Autopass extends ReadyResource {
|
|
|
269
292
|
onadd: async (candidate) => {
|
|
270
293
|
const id = candidate.inviteId
|
|
271
294
|
const inv = await this.base.view.findOne('@autopass/invite', {})
|
|
272
|
-
if (!b4a.equals(inv.id, id)) {
|
|
295
|
+
if (inv === null || !b4a.equals(inv.id, id)) {
|
|
273
296
|
return
|
|
274
297
|
}
|
|
275
298
|
candidate.open(inv.publicKey)
|
|
@@ -278,32 +301,63 @@ class Autopass extends ReadyResource {
|
|
|
278
301
|
key: this.base.key,
|
|
279
302
|
encryptionKey: this.base.encryptionKey
|
|
280
303
|
})
|
|
304
|
+
await this.deleteInvite()
|
|
281
305
|
}
|
|
282
306
|
})
|
|
283
307
|
this.swarm.join(this.base.discoveryKey)
|
|
308
|
+
|
|
309
|
+
const mirrorList = await this.getMirror()
|
|
310
|
+
const mirrors = mirrorList.map((item) => item.key)
|
|
311
|
+
this.peering = new BlindPeering(this.swarm, this.store, {
|
|
312
|
+
autobaseMirrors: mirrors
|
|
313
|
+
})
|
|
314
|
+
this.peering.addAutobaseBackground(this.base)
|
|
284
315
|
}
|
|
285
316
|
|
|
286
|
-
async add
|
|
287
|
-
await this.base.append(
|
|
317
|
+
async add(key, value, file) {
|
|
318
|
+
await this.base.append(encode('@autopass/put', { key, value, file }))
|
|
288
319
|
}
|
|
289
320
|
|
|
290
|
-
async
|
|
291
|
-
await this.base.append(
|
|
321
|
+
async remove(key) {
|
|
322
|
+
await this.base.append(encode('@autopass/del', { key }))
|
|
292
323
|
}
|
|
293
324
|
|
|
294
|
-
async
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
325
|
+
async addMirror(key) {
|
|
326
|
+
const keyBuffer = enc.decode(enc.normalize(key))
|
|
327
|
+
await this.base.append(encode('@autopass/add-mirror', { key: keyBuffer }))
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async getMirror() {
|
|
331
|
+
const queryStream = this.base.view.find('@autopass/mirrors', {})
|
|
332
|
+
const results = await queryStream.toArray()
|
|
333
|
+
return results.map((r) => ({
|
|
334
|
+
...r,
|
|
335
|
+
key: enc.encode(r.key)
|
|
336
|
+
}))
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async removeMirror(key) {
|
|
340
|
+
const keyBuffer = enc.decode(enc.normalize(key))
|
|
341
|
+
await this.base.append(encode('@autopass/del-mirror', { key: keyBuffer }))
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async suspend() {
|
|
345
|
+
if (this.swarm) {
|
|
346
|
+
await this.pairing.suspend()
|
|
347
|
+
await this.swarm.suspend()
|
|
348
|
+
await this.store.suspend()
|
|
298
349
|
}
|
|
299
|
-
return data.file
|
|
300
350
|
}
|
|
301
351
|
|
|
302
|
-
async
|
|
303
|
-
|
|
352
|
+
async resume() {
|
|
353
|
+
if (this.swarm) {
|
|
354
|
+
await this.store.resume()
|
|
355
|
+
await this.swarm.resume()
|
|
356
|
+
await this.pairing.resume()
|
|
357
|
+
}
|
|
304
358
|
}
|
|
305
359
|
} // end class
|
|
306
360
|
|
|
307
|
-
function noop
|
|
361
|
+
function noop() {}
|
|
308
362
|
|
|
309
363
|
module.exports = Autopass
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autopass",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"
|
|
6
|
+
"brittle": "npx brittle test.js",
|
|
7
|
+
"lint": "npx prettier . --check",
|
|
8
|
+
"test": "npm run lint && npm run brittle"
|
|
7
9
|
},
|
|
8
10
|
"author": "Holepunch Inc",
|
|
9
11
|
"license": "Apache-2.0",
|
|
@@ -19,25 +21,27 @@
|
|
|
19
21
|
}
|
|
20
22
|
},
|
|
21
23
|
"devDependencies": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"bare-fs": "^4.4.4",
|
|
25
|
+
"bare-process": "^4.2.1",
|
|
26
|
+
"brittle": "^3.19.0",
|
|
27
|
+
"hyperdht": "^6.23.0",
|
|
28
|
+
"prettier": "^3.6.2",
|
|
29
|
+
"prettier-config-holepunch": "^1.0.0",
|
|
30
|
+
"test-tmp": "^1.4.0"
|
|
26
31
|
},
|
|
27
32
|
"dependencies": {
|
|
28
|
-
"autobase": "^7.
|
|
29
|
-
"b4a": "^1.
|
|
30
|
-
"bare-fs": "^4.1.2",
|
|
31
|
-
"bare-process": "^4.2.1",
|
|
33
|
+
"autobase": "^7.19.4",
|
|
34
|
+
"b4a": "^1.7.1",
|
|
32
35
|
"blind-pairing": "^2.3.1",
|
|
33
|
-
"
|
|
34
|
-
"corestore": "^7.
|
|
35
|
-
"hyperbee": "^2.
|
|
36
|
-
"hypercore": "^11.
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
36
|
+
"blind-peering": "^1.13.0",
|
|
37
|
+
"corestore": "^7.4.7",
|
|
38
|
+
"hyperbee": "^2.26.5",
|
|
39
|
+
"hypercore": "^11.16.2",
|
|
40
|
+
"hypercore-id-encoding": "^1.3.0",
|
|
41
|
+
"hyperdb": "^4.16.1",
|
|
42
|
+
"hyperdispatch": "^1.4.2",
|
|
43
|
+
"hyperschema": "^1.15.0",
|
|
44
|
+
"hyperswarm": "^4.14.0",
|
|
45
|
+
"ready-resource": "^1.2.0"
|
|
42
46
|
}
|
|
43
47
|
}
|