Browse Source

initial commit, move code out of cobox-group

Kieran Gibb 2 years ago
commit
0845ccc1c9
No known key found for this signature in database
7 changed files with 2326 additions and 0 deletions
  1. 63
    0
      base.js
  2. 12
    0
      index.js
  3. 37
    0
      package.json
  4. 25
    0
      test/index.test.js
  5. 63
    0
      test/util.js
  6. 5
    0
      util.js
  7. 2121
    0
      yarn.lock

+ 63
- 0
base.js View File

@@ -0,0 +1,63 @@
1
+const multifeed = require('multifeed')
2
+const crypto = require('cobox-crypto')
3
+const Config = require('cobox-config')
4
+const constants = require('cobox-constants')
5
+const path = require('path')
6
+const RAM = require('random-access-memory')
7
+const RAF = require('random-access-file')
8
+const maybe = require('call-me-maybe')
9
+const debug = require('debug')('cobox-group')
10
+const { EventEmitter } = require('events')
11
+const assert = require('assert')
12
+
13
+class Base extends EventEmitter {
14
+  constructor (storage, address, opts = {}) {
15
+    super()
16
+
17
+    this.config = opts.config || Config(constants.storage)
18
+    this.address = crypto.toBuffer(address)
19
+
20
+    if (!crypto.isKey(address)) throw new Error('invalid: address format')
21
+
22
+    this._isTemp = storage && typeof storage !== 'string'
23
+    this._opts = opts
24
+
25
+    if (!this._isTemp) {
26
+      this.path = path.join(storage, this.address.toString('hex'))
27
+      this.storage = defaultStorage(this.path)
28
+    } else this.storage = RAM
29
+
30
+    this._isReady = false
31
+  }
32
+
33
+  ready (callback) {
34
+    var self = this
35
+    return maybe(callback, new Promise((resolve, reject) => {
36
+      self._readyCallback((err) => {
37
+        if (err) return reject(err)
38
+        self._isReady = true
39
+        return resolve()
40
+      })
41
+    }))
42
+  }
43
+
44
+  _initFeeds (_opts) {
45
+    this.multifeed = multifeed(this.storage, Object.assign(this._opts, _opts, {
46
+      encryptionKey: this.address
47
+    }))
48
+    this.replicate = this.multifeed.replicate.bind(this.multifeed)
49
+  }
50
+
51
+  bytesUsed () {
52
+    assert(this.multifeed, 'multifeed not yet initialised, call _initFeeds')
53
+    return this.multifeed.feeds().map(f => f.byteLength).reduce((a, b) => a + b)
54
+  }
55
+}
56
+
57
+function defaultStorage (dir) {
58
+  return function (name) {
59
+    return RAF(path.join(dir, name))
60
+  }
61
+}
62
+
63
+module.exports = Base

+ 12
- 0
index.js View File

@@ -0,0 +1,12 @@
1
+const Base = require('./base')
2
+
3
+class Encrypted extends Base {
4
+  constructor (storage, address, opts = {}) {
5
+    super(storage, address, opts)
6
+    this._initFeeds(opts)
7
+    this._readyCallback = this.multifeed.ready.bind(this.multifeed)
8
+  }
9
+}
10
+
11
+module.exports = (storage, address, opts = {}) => new Encrypted(storage, address, opts)
12
+module.exports.Base = Base

+ 37
- 0
package.json View File

@@ -0,0 +1,37 @@
1
+{
2
+  "name": "cobox-group-base",
3
+  "version": "0.1.0",
4
+  "description": "base group and blind replicator class",
5
+  "main": "index.js",
6
+  "scripts": {
7
+    "test": "tape test/**/*.test.js | tap-spec"
8
+  },
9
+  "repository": {
10
+    "type": "git",
11
+    "url": "https://ledger-git.dyne.org/cobox/cobox-group-base"
12
+  },
13
+  "keywords": [
14
+    "cobox"
15
+  ],
16
+  "author": "magma collective",
17
+  "license": "AGPL-3.0-or-later",
18
+  "dependencies": {
19
+    "assert": "^2.0.0",
20
+    "call-me-maybe": "^1.0.1",
21
+    "cobox-config": "git+https://ledger-git.dyne.org/CoBox/cobox-config#development",
22
+    "cobox-constants": "^1.0.0",
23
+    "cobox-crypto": "git+https://ledger-git.dyne.org/CoBox/cobox-crypto#development",
24
+    "debug": "^4.1.1",
25
+    "multifeed": "^5.1.0",
26
+    "random-access-file": "^2.1.3",
27
+    "random-access-memory": "^3.1.1"
28
+  },
29
+  "devDependencies": {
30
+    "nyc": "^14.1.1",
31
+    "rimraf": "^3.0.0",
32
+    "tap-spec": "^5.0.0",
33
+    "tape": "^4.11.0",
34
+    "tape-plus": "^1.0.0",
35
+    "tmp": "^0.1.0"
36
+  }
37
+}

+ 25
- 0
test/index.test.js View File

@@ -0,0 +1,25 @@
1
+const { describe } = require('tape-plus')
2
+const crypto = require('cobox-crypto')
3
+const path = require('path')
4
+
5
+const Encrypted = require('../')
6
+const { tmp, cleanup } = require('./util')
7
+
8
+describe('basic', (context) => {
9
+  context('create a blind group', async (assert, next) => {
10
+    var storage = tmp()
11
+    var address = crypto.address()
12
+    var group = Encrypted(storage, address)
13
+    assert.ok(group.config, 'has a config')
14
+    assert.ok(group.address, 'group created')
15
+    assert.ok(Buffer.isBuffer(group.address), 'address is a buffer')
16
+    assert.same(group.path, path.join(storage, address.toString('hex')))
17
+    assert.ok(group.storage, 'has random access file storage')
18
+    assert.ok(group.multifeed, 'has a multifeed instance')
19
+    assert.ok(typeof group.replicate === 'function', 'has a replicate function')
20
+
21
+    await group.ready()
22
+
23
+    cleanup(storage, next)
24
+  })
25
+})

+ 63
- 0
test/util.js View File

@@ -0,0 +1,63 @@
1
+const rimraf = require('rimraf')
2
+const debug = require('debug')('cleanup')
3
+const tmpdir = require('tmp').dirSync
4
+const mkdirp = require('mkdirp')
5
+
6
+function cleanup (dirs, cb) {
7
+  if (!cb) cb = noop
8
+  if (!Array.isArray(dirs)) dirs = [dirs]
9
+  var pending = 1
10
+
11
+  function next (n) {
12
+    var dir = dirs[n]
13
+    if (!dir) return done()
14
+    ++pending
15
+    process.nextTick(next, n + 1)
16
+
17
+    rimraf(dir, (err) => {
18
+      if (err) return done(err)
19
+      done()
20
+    })
21
+  }
22
+
23
+  function done (err) {
24
+    if (err) {
25
+      pending = Infinity
26
+      return cb(err)
27
+    }
28
+    if (!--pending) return cb()
29
+  }
30
+
31
+  next(0)
32
+}
33
+
34
+function tmp () {
35
+  var path = '.'+tmpdir().name
36
+  mkdirp.sync(path)
37
+  return path
38
+}
39
+
40
+function replicate (a, b, opts, cb) {
41
+  if (typeof opts === 'function') return replicate(a, b, {}, opts)
42
+  if (!cb) cb = noop
43
+
44
+  var s = a.replicate(true, Object.assign({ live: false }, opts))
45
+  var d = b.replicate(false, Object.assign({ live: false }, opts))
46
+
47
+  s.pipe(d).pipe(s)
48
+
49
+  s.on('error', (err) => {
50
+    if (err) return cb(err)
51
+  })
52
+
53
+  s.on('end', cb)
54
+}
55
+
56
+function uniq (array) {
57
+  if (!Array.isArray(array)) array = [array]
58
+  return Array.from(new Set(array))
59
+}
60
+
61
+function noop () {}
62
+
63
+module.exports = { cleanup, tmp, replicate, uniq }

+ 5
- 0
util.js View File

@@ -0,0 +1,5 @@
1
+function isFunction (variable) {
2
+  return typeof variable === 'function'
3
+}
4
+
5
+module.exports = { isFunction }

+ 2121
- 0
yarn.lock
File diff suppressed because it is too large
View File