little-network-box
Advanced tools
Comparing version 0.1.0 to 0.2.0
44
box.js
@@ -254,2 +254,12 @@ const { EventEmitter } = require('events') | ||
/** | ||
* Box instance Hypercore feed noise key pair accessor. | ||
* @public | ||
* @accessor | ||
* @type {?(Object)} | ||
*/ | ||
get noiseKeyPair() { | ||
return this.feed && this.feed.noiseKeyPair | ||
} | ||
/** | ||
* Box instance Hypercore feed stats accessor. | ||
@@ -265,2 +275,12 @@ * @public | ||
/** | ||
* Box instance Hypercore feed peers accessor. | ||
* @public | ||
* @accessor | ||
* @type {?(Object)} | ||
*/ | ||
get peers() { | ||
return this.feed && this.feed.peers | ||
} | ||
/** | ||
* Box instance Hypercore feed extensions accessor. | ||
@@ -554,15 +574,27 @@ * @public | ||
/** | ||
* Calls an extension on the Hypercore feed. | ||
* Calls `feed.extension(name, message)` | ||
* Registers extension hanlders by name on the Hypercore feed. | ||
* Calls `feed.registerExtension(name, handlers)` | ||
* @public | ||
* @method | ||
* @param {String} name | ||
* @param {Buffer} message} | ||
* @return {Mixed} | ||
* @param {Object<String,Function>} handlers | ||
* @return {Extension} | ||
*/ | ||
extension(name, message) { | ||
return this.feed.extension(name, message) | ||
registerExtension(name, handlers) { | ||
return this.feed.registerExtension(name, handlers) | ||
} | ||
/** | ||
* An alias to `registerExtension()` | ||
* @public | ||
* @method | ||
* @param {String} name | ||
* @param {Object<String,Function>} handlers | ||
* @return {Extension} | ||
*/ | ||
extension(name, handlers) { | ||
return this.registerExtension(name, handlers) | ||
} | ||
/** | ||
* Downloads data to Hypercore feed. | ||
@@ -569,0 +601,0 @@ * Calls `feed.download(range, callback)` |
const xsalsa20 = require('xsalsa20-encoding') | ||
function codec(opts) { | ||
const { nonce } = opts | ||
const key = opts.encryptionKey || opts.key | ||
return xsalsa20(nonce, key) | ||
const key = Buffer.from(opts.encryptionKey || opts.key).slice(0, 32) | ||
return xsalsa20(key) | ||
} | ||
module.exports = codec |
const secretbox = require('secretbox-encoding') | ||
function codec(opts) { | ||
const { nonce } = opts | ||
const key = opts.encryptionKey || opts.key | ||
return secretbox(nonce, key) | ||
const key = Buffer.from(opts.encryptionKey || opts.key).slice(0, 32) | ||
return secretbox(key) | ||
} | ||
module.exports = codec |
const xsalsa20 = require('hypercore-xsalsa20-onwrite-hook') | ||
const from = require('random-access-storage-from') | ||
function hook(opts) { | ||
const { nonce } = opts | ||
const key = opts.encryptionKey || opts.key | ||
return xsalsa20({ nonce, key }) | ||
function hook(box, opts) { | ||
const nonces = from(opts.nonces) | ||
const key = Buffer.from(opts.encryptionKey || opts.key).slice(0, 32) | ||
return xsalsa20(nonces, key) | ||
} | ||
module.exports = hook |
@@ -19,4 +19,20 @@ const HypercoreProtocol = require('hypercore-protocol') | ||
/** | ||
* Default options for a `Network` class instance. | ||
* @public | ||
* @static | ||
* @param {?(Object)} defaults | ||
* @param {...?(Object)} overrides | ||
* @return {Object} | ||
*/ | ||
static defaults(defaults, ...overrides) { | ||
return Object.assign({ | ||
encrypt: true, | ||
ack: true | ||
}, defaults, ...overrides) | ||
} | ||
/** | ||
*/ | ||
constructor(opts) { | ||
@@ -30,2 +46,4 @@ super() | ||
opts = this.constructor.defaults(opts) | ||
this.ondisconnection = bind(this, this.ondisconnection) | ||
@@ -49,2 +67,5 @@ this.onconnection = bind(this, this.onconnection) | ||
this.encrypt = Boolean(opts.encrypt) | ||
this.ack = Boolean(opts.ack) | ||
this.ready(this.onready) | ||
@@ -67,8 +88,4 @@ this.swarm.on('disconnection', this.ondisconnection) | ||
onconnection(socket, info) { | ||
const stream = new HypercoreProtocol({ | ||
// TODO | ||
encrypt: false, | ||
ack: true, | ||
live: true | ||
}) | ||
const { ack, live } = this | ||
const stream = new HypercoreProtocol(info.client, { ack, live }) | ||
@@ -75,0 +92,0 @@ this.emit('connection', stream, info, socket) |
23
node.js
@@ -45,4 +45,3 @@ const { replicate } = require('./replicate') | ||
/** | ||
* `Box.options` handler to ensure `nonce`, `discoveryKey`, | ||
* and `encryptionKey` are set. | ||
* `Box.options` handler to ensure `discoveryKey` and `encryptionKey` are set. | ||
* @private | ||
@@ -55,6 +54,2 @@ * @method | ||
if (null !== opts.nonce) { | ||
opts.nonce = toBuffer(opts.nonce || crypto.randomBytes(24), 'hex') | ||
} | ||
if (null !== opts.discoveryKey) { | ||
@@ -81,4 +76,6 @@ opts.discoveryKey = toBuffer(opts.discoveryKey, 'hex') | ||
this.encryptionKey = opts.encryptionKey | ||
this.nonce = opts.nonce | ||
this.shouldUpload = Boolean(opts.upload) | ||
this.shouldDownload = Boolean(opts.download) | ||
if (false !== opts.network) { | ||
@@ -98,7 +95,6 @@ this.network = opts.network || new Network(opts) | ||
[Box.codec](opts) { | ||
const { encryptionKey, nonce } = opts | ||
if (encryptionKey && nonce) { | ||
assert(Buffer.isBuffer(nonce)) | ||
const { encryptionKey } = opts | ||
if (encryptionKey) { | ||
assert(Buffer.isBuffer(encryptionKey)) | ||
return codecs.xsalsa20({ encryptionKey, nonce }) | ||
return codecs.xsalsa20({ encryptionKey }) | ||
} | ||
@@ -175,4 +171,5 @@ } | ||
const { download, upload, encrypt, live } = this | ||
const { isOrigin, discoveryKey } = this | ||
const download = this.shouldDownload | ||
const upload = this.shouldUpload | ||
const { isOrigin, live, discoveryKey } = this | ||
const initiator = info.client | ||
@@ -179,0 +176,0 @@ const topic = info.peer && info.peer.topic |
const { Node } = require('./node') | ||
const extend = require('extend') | ||
const hooks = require('./hooks') | ||
const ram = require('random-access-memory') | ||
@@ -28,4 +30,26 @@ /** | ||
origin: true, | ||
nonces: null, | ||
hooks: [], | ||
}, defaults, ...overrides) | ||
} | ||
/** | ||
* @protected | ||
*/ | ||
[Node.init](opts) { | ||
super[Node.init](opts) | ||
this.nonces = opts.nonces | ||
} | ||
[Node.options](opts) { | ||
super[Node.options](opts) | ||
if (opts.encryptionKey && opts.nonces) { | ||
opts.hooks.push(hooks.xsalsa20) | ||
} | ||
} | ||
[Node.codec](opts) { | ||
return null | ||
} | ||
} | ||
@@ -32,0 +56,0 @@ |
{ | ||
"name": "little-network-box", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "A little toolkit for distributed applications.", | ||
@@ -8,3 +8,3 @@ "main": "index.js", | ||
"little-network-box": "bin/little-network-box", | ||
"little-box": "bin/little-network-box" | ||
"lnb": "bin/little-network-box" | ||
}, | ||
@@ -32,9 +32,10 @@ "scripts": { | ||
"get-uri": "^2.0.3", | ||
"hypercore": "^7.7.1", | ||
"hypercore": "^8.4.1", | ||
"hypercore-block-request": "^0.2.0", | ||
"hypercore-protocol": "^6.12.0", | ||
"hypercore-indexed-file": "^0.1.2", | ||
"hypercore-protocol": "^7.7.1", | ||
"hypercore-ready": "^0.2.0", | ||
"hypercore-replicate": "^0.3.0", | ||
"hypercore-xsalsa20-onwrite-hook": "^0.2.0", | ||
"hyperswarm": "^2.3.1", | ||
"hypercore-xsalsa20-onwrite-hook": "^1.0.2", | ||
"hyperswarm": "^2.4.0", | ||
"minimist": "^1.2.0", | ||
@@ -51,2 +52,3 @@ "mutexify": "^1.2.0", | ||
"random-access-s3": "^1.0.0", | ||
"random-access-storage-from": "^0.1.1", | ||
"rimraf": "^3.0.0", | ||
@@ -58,3 +60,3 @@ "rpc-protocol": "^0.2.2", | ||
"to-buffer": "^1.1.1", | ||
"xsalsa20-encoding": "^0.1.0" | ||
"xsalsa20-encoding": "^1.0.1" | ||
}, | ||
@@ -61,0 +63,0 @@ "optionalDependencies": {}, |
@@ -15,4 +15,6 @@ little-network-box | ||
> WIP | ||
[![Actions Status](https://github.com/little-core-labs/little-network-box/workflows/Node%20CI/badge.svg)](https://github.com/little-core-labs/little-network-box/actions) | ||
> **Development/Testing/Documentation** | ||
## Example | ||
@@ -28,12 +30,13 @@ | ||
const video = path.resolve(__dirname, 'video.mp4') | ||
const copy = path.resolve(__dirname, 'copy.mp4') | ||
const origin = new Origin(ram) | ||
const nonces = ram() | ||
const source = path.resolve(__dirname, 'video.mp4') | ||
const destination = path.resolve(__dirname, 'copy.mp4') | ||
const origin = new Origin(ram, { nonces }) | ||
origin.ready(() => { | ||
const input = origin.createWriteStream() | ||
const video = fs.createReadStream(video, { highWaterMark: 1024 }) | ||
const sink = new Sink(copy, origin.key, { | ||
const video = fs.createReadStream(source) | ||
const sink = new Sink(destination, origin.key, { | ||
encryptionKey: origin.encryptionKey, | ||
nonce: origin.nonce | ||
nonces: origin.nonces | ||
}) | ||
@@ -44,3 +47,2 @@ | ||
if (sink.byteLength === origin.byteLength) { | ||
console.log('sync') | ||
sink.close() | ||
@@ -279,37 +281,19 @@ origin.close() | ||
const encoding = require('xsalsa20-encoding') | ||
const xsalsa20 = require('xsalsa20') | ||
const crypto = require('crypto') | ||
const nonce = crypto.randomBytes(24) | ||
const secret = crypto.randomBytes(32) | ||
// encrypts plaintext into ciphertext before writing | ||
// to storage | ||
// encrypts plaintext into ciphertext before writing to storage | ||
class EncryptedBox extends Box { | ||
[Box.codec](opts) { | ||
return encoding(nonce, opts.key) | ||
return encoding(opts.secret) | ||
} | ||
} | ||
// decrypts data before writing to storage so | ||
// `get()`, `head()`, etc return plaintext | ||
class DecryptedBox extends Box { | ||
[Box.write](index, data, peer, done) { | ||
try { | ||
const xor = xsalsa20(nonce, this.key) | ||
xor.update(data, data) | ||
xor.finalize() | ||
done(null) | ||
} catch (err) { | ||
done(err) | ||
} | ||
} | ||
} | ||
const encrypted = new EncryptedBox(ram) | ||
const encrypted = new EncryptedBox(ram, { secret }) | ||
encrypted.ready(() => { | ||
const decrypted = new DecryptedBox(ram, encrypted.key) | ||
decrypted.ready(() => { | ||
replicate(encrypted, decrypted, (err) => { | ||
decrypted.head(console.log) // hello world | ||
}) | ||
const decrypted = new EncryptedBox(ram, { secret }) | ||
encrypted.append(Buffer.from('hello world')) | ||
replicate(encrypted, decrypted, (err) => { | ||
decrypted.head(console.log) // hello world | ||
}) | ||
@@ -426,3 +410,3 @@ }) | ||
[Box.codec](opts) { | ||
return xsalsa20(opts.nonce, opts.key) | ||
return xsalsa20(opts.secret) | ||
} | ||
@@ -435,4 +419,4 @@ | ||
const nonce = crypto.randomBytes(24) | ||
const trie = new EncryptedOriginTrieBox(ram, { nonce }) | ||
const secret = crypto.randomBytes(32) | ||
const trie = new EncryptedOriginTrieBox(ram, { secret }) | ||
trie.put('hello', 'world', (err) => { | ||
@@ -464,6 +448,2 @@ trie.get('hello', console.log) // { ..., key: 'hello', value: 'world' } | ||
#### `node.nonce` | ||
Nonce used for the XSalsa20 cipher to encrypt storage data. | ||
### `const options = Node.defaults(defaults, ...overrides)` | ||
@@ -627,4 +607,3 @@ | ||
class will decode data using the XSalsa20 cipher for decryption | ||
before writing to data storage if an `encryptionKey` and `nonce` | ||
is given. | ||
before writing to data storage if an `encryptionKey` is given. | ||
@@ -649,3 +628,4 @@ #### Usage | ||
overwrite: true, | ||
nonce: null, | ||
nonces: null, | ||
hooks: [] | ||
} | ||
@@ -670,7 +650,4 @@ ``` | ||
[hypercore]: https://github.com/mafintosh/hypercore | ||
[hyperswarm]: https://github.com/hyperswarm/hyperswarm | ||
[random-access-storage]: https://github.com/random-access-storage/random-access-storage | ||
43
sink.js
const { Node } = require('./node') | ||
const { sink } = require('./storage') | ||
const { Box } = require('./box') | ||
const codecs = require('./codecs') | ||
const extend = require('extend') | ||
const hooks = require('./hooks') | ||
const hooks = require('./hooks') | ||
const ram = require('random-access-memory') | ||
@@ -12,3 +14,3 @@ /** | ||
* class will decode data using the XSalsa20 cipher for decryption | ||
* before writing to data storage if an `encryptionKey` and `nonce` | ||
* before writing to data storage if an `encryptionKey` and `nonces` | ||
* is given. | ||
@@ -33,3 +35,4 @@ * @public | ||
overwrite: true, | ||
nonce: null, | ||
nonces: null, | ||
hooks: [], | ||
}, defaults, ...overrides) | ||
@@ -39,2 +42,21 @@ } | ||
/** | ||
* `Box.init` handler to initialize `Node` instance. | ||
* @private | ||
* @method | ||
* @param {Object} opts | ||
*/ | ||
[Box.init](opts) { | ||
super[Box.init](opts) | ||
this.nonces = opts.nonces | ||
} | ||
[Box.options](opts) { | ||
super[Box.options](opts) | ||
if (opts.encryptionKey && opts.nonces) { | ||
opts.hooks.push(hooks.xsalsa20) | ||
} | ||
} | ||
/** | ||
* `Box.codec` handler to return empty encoding | ||
@@ -54,17 +76,2 @@ * @private | ||
} | ||
/** | ||
* Decodes data using XSalsa20 cipher if | ||
* `encryptionKey` and `nonce` were given. | ||
* @private | ||
*/ | ||
[Box.write](index, data, peer, done) { | ||
const { encryptionKey, nonce, feed } = this | ||
if (encryptionKey && nonce) { | ||
const hook = hooks.xsalsa20(this) | ||
return hook.call(feed, index, data, peer, done) | ||
} else { | ||
return done(null) | ||
} | ||
} | ||
} | ||
@@ -71,0 +78,0 @@ |
@@ -6,4 +6,6 @@ const { EventEmitter } = require('events') | ||
const storage = require('./storage') | ||
const codecs = require('./codecs') | ||
const extend = require('extend') | ||
const debug = require('debug')('little-network-box:source') | ||
const hooks = require('./hooks') | ||
const pump = require('pump') | ||
@@ -42,3 +44,2 @@ const get = require('get-uri') | ||
indexing: true, | ||
nonce: null | ||
}, defaults, ...overrides) | ||
@@ -56,3 +57,3 @@ } | ||
try { | ||
if ('file:' !== u.protocol) { | ||
if (!u.protocol) { | ||
fs.accessSync(opts.uri) | ||
@@ -68,3 +69,3 @@ u.protocol = 'file:' | ||
/** | ||
* @private | ||
* @protected | ||
*/ | ||
@@ -71,0 +72,0 @@ [Box.init](opts) { |
Sorry, the diff of this file is not supported yet
76044
2067
33
644
+ Added@sammacbeth/random-access-idb-mutable-file@0.1.1(transitive)
+ Addedabstract-extension@3.1.1(transitive)
+ Addedbare-events@2.5.4(transitive)
+ Addedbuffer@5.1.0(transitive)
+ Addedbuffer-from@0.1.2(transitive)
+ Addedbytes@3.0.0(transitive)
+ Addedclone@2.1.2(transitive)
+ Addedcontent-disposition@0.5.2(transitive)
+ Addedfast-fifo@1.3.2(transitive)
+ Addedhmac-blake2b@0.2.0(transitive)
+ Addedhypercore@8.14.0(transitive)
+ Addedhypercore-cache@1.0.2(transitive)
+ Addedhypercore-indexed-file@0.1.3(transitive)
+ Addedhypercore-protocol@7.10.0(transitive)
+ Addedhypercore-xsalsa20-onwrite-hook@1.0.2(transitive)
+ Addedis-browser@2.1.0(transitive)
+ Addedmime-db@1.33.0(transitive)
+ Addedmime-types@2.1.18(transitive)
+ Addednext-tick@1.1.0(transitive)
+ Addednoise-protocol@1.0.0(transitive)
+ Addedpath-is-inside@1.0.2(transitive)
+ Addedpath-to-regexp@3.3.0(transitive)
+ Addedrandom-access-chrome-file@1.2.0(transitive)
+ Addedrandom-access-idb@1.2.2(transitive)
+ Addedrandom-access-idb-mutable-file@0.3.0(transitive)
+ Addedrandom-access-storage@1.3.0(transitive)
+ Addedrandom-access-storage-from@0.1.1(transitive)
+ Addedrandom-access-web@2.0.3(transitive)
+ Addedrange-parser@1.2.0(transitive)
+ Addedserve-handler@6.1.6(transitive)
+ Addedsimple-handshake@1.3.1(transitive)
+ Addedsimple-hypercore-protocol@1.5.0(transitive)
+ Addedsimple-message-channels@1.2.1(transitive)
+ Addedstreamx@2.21.1(transitive)
+ Addedtext-decoder@1.2.3(transitive)
+ Addedxsalsa20-encoding@1.1.0(transitive)
- Removedarray-lru@1.1.1(transitive)
- Removedhypercore@7.7.1(transitive)
- Removedhypercore-protocol@6.12.0(transitive)
- Removedhypercore-xsalsa20-onwrite-hook@0.2.0(transitive)
- Removedsorted-indexof@1.0.0(transitive)
- Removedxsalsa20-encoding@0.1.1(transitive)
Updatedhypercore@^8.4.1
Updatedhypercore-protocol@^7.7.1
Updatedhyperswarm@^2.4.0
Updatedxsalsa20-encoding@^1.0.1