cobox-config
Advanced tools
Comparing version 2.0.0 to 2.1.0
41
index.js
@@ -7,6 +7,10 @@ const yaml = require('js-yaml') | ||
const logger = require('./logger') | ||
const crypto = require('cobox-crypto') | ||
const constants = require('cobox-constants') | ||
const CONFIG_FILE = 'config.yml' | ||
const IDENTITY_SUBKEY_ID = 0 | ||
module.exports = (storage, opts) => new CoBoxConfig(storage, opts) | ||
module.exports.IDENTITY_SUBKEY_ID = IDENTITY_SUBKEY_ID | ||
@@ -16,9 +20,6 @@ const KeyHandler = require('./lib/key-handler') | ||
const defaultOptions = () => ({ | ||
mount: '/cobox' | ||
}) | ||
const defaultConfig = () => ({ | ||
options: defaultOptions(), | ||
const defaultConfig = (options = {}) => ({ | ||
options, | ||
groups: { byKey: {}, byName: {} }, | ||
replicators: { byKey: {}, byName: {} }, | ||
identities: { byKey: {}, byName: {} } | ||
@@ -32,10 +33,9 @@ }) | ||
constructor (storage, opts = {}) { | ||
this.root = storage || path.join(os.homedir(), '.cobox') | ||
this.root = storage || constants.storage | ||
this.storage = path.join(this.root, CONFIG_FILE) | ||
this.secrets = path.join(this.root, 'secret_keys') | ||
this._opts = opts | ||
mkdirp.sync(path.join(this.root, 'logs')) | ||
mkdirp.sync(this.secrets) | ||
var config = Object.assign(defaultConfig(), opts.seeds || {}) | ||
var config = Object.assign(defaultConfig()) | ||
@@ -45,2 +45,3 @@ if (!fs.existsSync(this.storage)) { | ||
this._groups = config.groups | ||
this._replicators = config.replicators | ||
this._identities = config.identities | ||
@@ -52,6 +53,15 @@ this._options = config.options | ||
var masterKeyPath = path.join(this.root, 'master_key') | ||
if (!fs.existsSync(masterKeyPath)) { | ||
this.masterKey = crypto.masterKey() | ||
fs.writeFileSync(masterKeyPath, this.masterKey, { mode: fs.constants.S_IRUSR }) | ||
} else { | ||
this.masterKey = fs.readFileSync(masterKeyPath) | ||
} | ||
this.identity = crypto.keyPair(this.masterKey, IDENTITY_SUBKEY_ID) | ||
this.logger = logger(path.join(this.root, 'logs', logfile)) | ||
this.log = this.logger('cobox-config') | ||
this.groups = KeyHandler(this._groups) | ||
this.replicators = KeyHandler(this._replicators) | ||
this.identities = KeyHandler(this._identities) | ||
@@ -65,2 +75,3 @@ this.options = MapHandler(this._options) | ||
config.groups = this._groups | ||
config.replicators = this._replicators | ||
config.identities = this._identities | ||
@@ -82,3 +93,4 @@ config.options = this._options | ||
this._identities = config.identities | ||
this._options = config.options || defaultOptions() | ||
this._replicators = config.replicators | ||
this._options = config.options | ||
return true | ||
@@ -91,6 +103,1 @@ } catch (err) { | ||
} | ||
function storeSecret (location, secret) { | ||
fs.writeFileSync(secretKey, Buffer.from(secret)) | ||
return location | ||
} |
@@ -1,6 +0,5 @@ | ||
const Crypto = require('cobox-crypto') | ||
const crypto = require('cobox-crypto') | ||
const { isPubKey, isName } = require('../util') | ||
const KEY_NAMES = ['publicKey', 'encryptionKey', 'secretKey', 'symmetricKey'] | ||
const crypto = Crypto() | ||
const KEY_NAMES = ['name', 'address', 'encryptionKey'] | ||
@@ -22,4 +21,4 @@ const KeyHandler = module.exports = (collection) => ({ | ||
}) | ||
if (crypto.isKey(id)) collection.byKey[id.toString('hex')] = clone | ||
if (isName(id)|| clone.name) collection.byName[clone.name] = clone | ||
if (crypto.isKey(clone.address)) collection.byKey[clone.address.toString('hex')] = clone | ||
if (isName(clone.name)) collection.byName[clone.name] = clone | ||
return true | ||
@@ -32,7 +31,7 @@ }, | ||
if (entry.name) delete collection.byName[entry.name] | ||
return delete collection.byKey[entry.publicKey.toString('hex')] | ||
return delete collection.byKey[entry.address.toString('hex')] | ||
} else if (isName(id)) { | ||
entry = collection.byName[id] | ||
if (!entry) return false | ||
return delete collection.byName[id] && delete collection.byKey[entry.publicKey.toString('hex')] | ||
return delete collection.byName[id] && delete collection.byKey[entry.address.toString('hex')] | ||
} | ||
@@ -57,7 +56,6 @@ }, | ||
function isValid (entry) { | ||
return entry.publicKey | ||
&& crypto.isKey(entry.publicKey) | ||
return entry.address | ||
&& crypto.isKey(entry.address) | ||
&& !entry.encryptionKey || crypto.isKey(entry.encryptionKey) | ||
&& !entry.symmetricKey || crypto.isKey(entry.symmetricKey) | ||
&& !entry.name || isName(entry.name) | ||
} |
{ | ||
"name": "cobox-config", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "load and save a cobox configuration", | ||
@@ -10,3 +10,4 @@ "main": "index.js", | ||
"dependencies": { | ||
"cobox-crypto": "git+ssh://git@ledger-git.dyne.org:2240/CoBox/cobox-crypto.git", | ||
"cobox-crypto": "^1.2.0", | ||
"cobox-constants": "^1.0.1", | ||
"debug": "^4.1.1", | ||
@@ -20,2 +21,3 @@ "js-yaml": "^3.13.1", | ||
"devDependencies": { | ||
"hypercore-crypto": "^1.0.0", | ||
"nyc": "^14.1.1", | ||
@@ -34,3 +36,3 @@ "rimraf": "^2.6.3", | ||
"type": "git", | ||
"url": "git+https://github.com/coboxcoop/cobox-config.git" | ||
"url": "git+https://ledger-git.dyne.org/cobox/cobox-config" | ||
}, | ||
@@ -41,3 +43,3 @@ "keywords": [ | ||
], | ||
"author": "kyphae", | ||
"author": "magma collective", | ||
"license": "AGPL-3", | ||
@@ -44,0 +46,0 @@ "bugs": { |
# cobox-config | ||
Stores and retrieves a YAML configuration file for use with the cobox stack. | ||
Stores and retrieves a YAML configuration file for use with the cobox stack. Also loads up master key to generate a global identity. | ||
@@ -9,5 +9,5 @@ ## Example | ||
const Config = require('cobox-config') | ||
const crypto = require('cobox-crypto') // or some other crypto scheme | ||
const crypto = require('cobox-crypto')() // or some other crypto scheme | ||
var storage = './storage' | ||
var storage = './storage' | ||
var config = Config(storage) | ||
@@ -31,17 +31,18 @@ ``` | ||
``` | ||
config.identities.add(identity) | ||
var key = group.name || group.address || group.address.toString('hex') | ||
config.groups.get(group) | ||
``` | ||
Append an identity to the config | ||
Get a group from the config | ||
``` | ||
var key = identity.name || identity.publicKey || identity.publicKey.toString('hex') | ||
config.identities.remove(key) | ||
var key = group.name || group.address || group.address.toString('hex') | ||
config.groups.set(group, { name, address, encryptionKey }) | ||
``` | ||
Remove an identity from the config | ||
Add a group to the config | ||
``` | ||
var key = group.name || group.publicKey || group.publicKey.toString('hex') | ||
config.groups.remove(group) | ||
var key = group.name || group.address || group.address.toString('hex') | ||
config.groups.delete(group) | ||
``` | ||
@@ -52,8 +53,2 @@ | ||
``` | ||
config.identities.list() | ||
``` | ||
List saved identities | ||
``` | ||
config.groups.list() | ||
@@ -64,5 +59,3 @@ ``` | ||
## Todos | ||
* [ ] encode public keys as base64 urlsafe in YAML | ||
* [ ] store the path to secret key file (base64 urlsafe binary encoding) instead of raw secret key in the config file | ||
## Future Features | ||
* Store names against ID's in YAML config file for multiple identity capability |
const { describe } = require('tape-plus') | ||
const Config = require('../') | ||
const crypto = require('cobox-crypto')() | ||
const crypto = require('cobox-crypto') | ||
const fs = require('fs') | ||
@@ -10,209 +10,59 @@ const path = require('path') | ||
describe('load', (context) => { | ||
var storage | ||
context.beforeEach((c) => { | ||
storage = tmp() | ||
describe('exports', (context) => { | ||
context('IDENTITY_SUBKEY_ID', (assert, next) => { | ||
assert.same(Config.IDENTITY_SUBKEY_ID, 0, 'exports IDENTITY_SUBKEY_ID') | ||
next() | ||
}) | ||
}) | ||
context.afterEach((c) => { | ||
cleanup(storage) | ||
}) | ||
describe('load', (context) => { | ||
context('default', (assert, next) => { | ||
var storage = tmp() | ||
var config = Config(storage) | ||
assert.ok(config.identities.list() instanceof Array, 'identities list defaults to empty Array') | ||
assert.ok(config.groups.list() instanceof Array, 'groups list defaults to empty Array') | ||
assert.ok(config.replicators.list() instanceof Array, 'replicators list defaults to empty Array') | ||
next() | ||
cleanup(storage, next) | ||
}) | ||
}) | ||
describe('options', (context) => { | ||
var storage | ||
context.beforeEach((c) => { | ||
storage = tmp() | ||
}) | ||
context.afterEach((c) => { | ||
cleanup(storage.root) | ||
}) | ||
context('get', (assert, next) => { | ||
describe('master_key', (context) => { | ||
context('default', (assert, next) => { | ||
var storage = tmp() | ||
var config = Config(storage) | ||
assert.same(config.options.get('mount'), '/cobox', 'mount defaults to /cobox') | ||
next() | ||
}) | ||
context('set', (assert, next) => { | ||
var config = Config(storage) | ||
config.options.set('mount', './mnt') | ||
assert.same(config._options['mount'], './mnt', 'sets mount option to ./mnt') | ||
config.save() | ||
config.load() | ||
assert.same(config.options.get('mount'), './mnt', 'saved options') | ||
next() | ||
}) | ||
}) | ||
var masterKey = config.masterKey | ||
assert.ok(masterKey, 'generates a master key') | ||
describe('set', (context) => { | ||
var storage | ||
fs.readFile(path.join(storage, 'master_key'), (err, data) => { | ||
assert.same(Buffer.from(data).toString('hex'), masterKey.toString('hex'), 'keys match') | ||
context.beforeEach((c) => { | ||
storage = tmp() | ||
}) | ||
fs.writeFile(path.join(storage, 'master_key'), 'Woof Woof', (err) => { | ||
assert.ok(err, 'throws an error') | ||
assert.ok(err.code, 'EACCES', 'invalid permissions') | ||
assert.ok(err.message, `permission denied, open '${storage}'`) | ||
context.afterEach((c) => { | ||
cleanup(storage) | ||
cleanup(storage, next) | ||
}) | ||
}) | ||
}) | ||
context('byKey', (assert, next) => { | ||
context('reload', (assert, next) => { | ||
var storage = tmp() | ||
var config = Config(storage) | ||
var group = crypto.unpack(crypto.accessKey()) | ||
var identity = crypto.keyPair() | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
var reload = yaml.safeLoad(fs.readFileSync(path.join(storage, 'config.yml'))) | ||
var rawGroup = reload.groups.byKey[group.publicKey.toString('hex')] | ||
var rawIdentity = reload.identities.byKey[identity.publicKey.toString('hex')] | ||
assert.same(config.groups.get(group.publicKey), rawGroup, 'saves groups to storage') | ||
assert.same(config.identities.get(identity.publicKey), rawIdentity, 'saves identities to storage') | ||
next() | ||
var masterKey = config.masterKey | ||
config = Config(storage) | ||
var key = config.masterKey | ||
assert.same(key, masterKey, 'reloads the same master_key') | ||
cleanup(storage, next) | ||
}) | ||
context('byName', (assert, next) => { | ||
var config = Config(storage) | ||
var group = Object.assign({ name: 'group-a' }, crypto.unpack(crypto.accessKey())) | ||
var identity = Object.assign({ name: 'Alice' }, crypto.keyPair()) | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
var reload = yaml.safeLoad(fs.readFileSync(path.join(storage, 'config.yml'))) | ||
var rawGroup = reload.groups.byKey[group.publicKey.toString('hex')] | ||
var rawIdentity = reload.identities.byKey[identity.publicKey.toString('hex')] | ||
assert.ok(rawGroup.name, 'saves group with a name') | ||
assert.same(config.groups.get(group.name), rawGroup, 'gets the group using a name') | ||
assert.ok(rawIdentity.name, 'saves identity with a name') | ||
assert.same(config.identities.get(identity.name), rawIdentity, 'saves identities to storage') | ||
var reload = Config(storage) | ||
assert.same(reload._groups, config._groups, 'load groups from storage') | ||
assert.same(reload._identities, config._identities, 'load identities from storage') | ||
next() | ||
}) | ||
}) | ||
describe('get', (context) => { | ||
var storage | ||
context.beforeEach((c) => { | ||
storage = tmp() | ||
describe('options', (context) => { | ||
context('reload', (assert, next) => { | ||
var storage = tmp() | ||
var config = Config(storage, { hello: true }) | ||
assert.notOk(config.options.get('hello'), 'options must be manually set') | ||
cleanup(storage, next) | ||
}) | ||
context.afterEach((c) => { | ||
cleanup(storage) | ||
}) | ||
context('works with buffers or strings', (assert, next) => { | ||
var config = Config(storage) | ||
var group = crypto.unpack(crypto.accessKey()) | ||
var identity = crypto.keyPair() | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
assert.ok(config.groups.get(group.publicKey), 'get group works with a buffer') | ||
assert.ok(config.groups.get(group.publicKey.toString('hex')), 'get group works with a hex') | ||
assert.ok(config.identities.get(identity.publicKey), 'get identity works with a buffer') | ||
assert.ok(config.identities.get(identity.publicKey.toString('hex')), 'get identity works with a hex') | ||
next() | ||
}) | ||
}) | ||
describe('del', (context) => { | ||
var storage | ||
context.beforeEach((c) => { | ||
storage = tmp() | ||
}) | ||
context.afterEach((c) => { | ||
cleanup(storage) | ||
}) | ||
context('deletes relevant entry using buffers', (assert, next) => { | ||
var config = Config(storage) | ||
var group = crypto.unpack(crypto.accessKey()) | ||
var identity = crypto.keyPair() | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
config.load() | ||
config.groups.delete(group.publicKey) | ||
config.identities.delete(identity.publicKey) | ||
assert.same(config.groups.list(), [], 'deleted the group') | ||
assert.same(config.identities.list(), [], 'deleted the identity') | ||
next() | ||
}) | ||
context('deletes relevant entry using buffers', (assert, next) => { | ||
var config = Config(storage) | ||
var group = crypto.unpack(crypto.accessKey()) | ||
var identity = crypto.keyPair() | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
config.load() | ||
config.groups.delete(group.publicKey.toString('hex')) | ||
config.identities.delete(identity.publicKey.toString('hex')) | ||
assert.same(config.groups.list(), [], 'deleted the group') | ||
assert.same(config.identities.list(), [], 'deleted the identity') | ||
next() | ||
}) | ||
context('deletes relevant entry using names', (assert, next) => { | ||
var config = Config(storage) | ||
var group = Object.assign({ name: 'group-a' }, crypto.unpack(crypto.accessKey())) | ||
var identity = Object.assign({ name: 'Alice' }, crypto.keyPair()) | ||
config.groups.set(group.publicKey, group) | ||
config.identities.set(identity.publicKey, identity) | ||
config.save() | ||
config.load() | ||
assert.same(config.groups.list().length, 1, 'saved the group') | ||
assert.same(config.identities.list().length, 1, 'saved the identity') | ||
config.groups.delete(group.name) | ||
config.identities.delete(identity.name) | ||
config.save() | ||
config.load() | ||
assert.same(config.groups.list(), [], 'deleted the group') | ||
assert.same(config.identities.list(), [], 'deleted the identity') | ||
next() | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable and can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
122606
13
0
8
7
352
58
4
+ Addedcobox-constants@^1.0.1
+ Added@noble/hashes@1.7.1(transitive)
+ Addedassert@2.1.0(transitive)
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedb4a@1.6.7(transitive)
+ Addedbip39@3.1.0(transitive)
+ Addedblake2b@2.1.4(transitive)
+ Addedblake2b-wasm@2.4.0(transitive)
+ Addedbuffer-alloc@1.2.0(transitive)
+ Addedbuffer-alloc-unsafe@1.1.0(transitive)
+ Addedbuffer-fill@1.0.0(transitive)
+ Addedbuffer-from@1.1.2(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addedcobox-constants@1.0.3(transitive)
+ Addedcobox-crypto@1.2.5(transitive)
+ Addedcodecs@2.2.0(transitive)
+ Addedcrypto-encoder@1.0.2(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddefine-properties@1.2.1(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedfor-each@0.3.4(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhypercore-crypto@1.0.0(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedini@1.3.8(transitive)
+ Addedis-arguments@1.2.0(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-generator-function@1.1.0(transitive)
+ Addedis-nan@1.3.2(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedis-typed-array@1.1.15(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addednan@2.22.0(transitive)
+ Addednanoassert@1.1.02.0.0(transitive)
+ Addednode-gyp-build@4.8.4(transitive)
+ Addedobject-is@1.1.6(transitive)
+ Addedobject-keys@1.1.1(transitive)
+ Addedobject.assign@4.1.7(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedsafe-regex-test@1.1.0(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedsiphash24@1.3.1(transitive)
+ Addedsodium-javascript@0.5.6(transitive)
+ Addedsodium-native@2.4.9(transitive)
+ Addedsodium-universal@2.0.0(transitive)
+ Addeduint64be@2.0.2(transitive)
+ Addedutil@0.12.5(transitive)
+ Addedwhich-typed-array@1.1.18(transitive)
+ Addedxsalsa20@1.2.0(transitive)
Updatedcobox-crypto@^1.2.0