mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Use orbit-common. Make test fully independent and not require orbit-server to be running.
This commit is contained in:
parent
2f1c13ee42
commit
f74ec4b104
27
README.md
27
README.md
@ -1,20 +1,24 @@
|
||||
# orbit-client
|
||||
# OrbitDB
|
||||
|
||||
## Introduction
|
||||
|
||||
Key-Value Store and Event Store on IPFS.
|
||||
Distributed, peer-to-peer* Key-Value Store and Event Log on IPFS.
|
||||
|
||||
Requires `orbit-server` to connect to. Get from https://github.com/haadcode/orbit-server.
|
||||
|
||||
_* Currently requires a centralized server. This will change in the future as required p2p features land in IPFS_
|
||||
|
||||
## Features
|
||||
- Distributed kv-store and event log database
|
||||
- Stores all data in IPFS
|
||||
- Data encrypted on the wire and at rest
|
||||
- Per channel access rights
|
||||
|
||||
_Channel maps to "table", "keyspace", "topic" or "feed" in similar systems_
|
||||
_Channel is similar to "table", "keyspace", "topic", "feed" or "collection" in other systems_
|
||||
|
||||
## API
|
||||
_See Usage below_
|
||||
|
||||
connect(host, username, password)
|
||||
|
||||
channel(name, password)
|
||||
@ -36,7 +40,7 @@ _Channel maps to "table", "keyspace", "topic" or "feed" in similar systems_
|
||||
|
||||
.get(key) // Retrieve value
|
||||
|
||||
.remove({ key: <key>, hash: <event's ipfs-hash> }) // Remove entry (use one option)
|
||||
.remove({ key: <key or hash> }) // Remove entry
|
||||
|
||||
.setMode(modes) // Set channel modes, can be an object or an array of objects
|
||||
|
||||
@ -62,11 +66,9 @@ async(() => {
|
||||
|
||||
const channelName = 'hello-world';
|
||||
|
||||
// Send an event
|
||||
const head = orbit.channel(channelName).add('hello'); // <ipfs-hash>
|
||||
|
||||
// Delete an event
|
||||
orbit.channel(channelName).remove(head);
|
||||
/* Event Log */
|
||||
const hash = orbit.channel(channelName).add('hello'); // <ipfs-hash>
|
||||
orbit.channel(channelName).remove({ key: hash });
|
||||
|
||||
// Iterator options
|
||||
const options = { limit: -1 }; // fetch all messages
|
||||
@ -82,11 +84,12 @@ async(() => {
|
||||
// for(let i of iter)
|
||||
// console.log(i.hash, i.item);
|
||||
|
||||
// KV-store
|
||||
/* KV Store */
|
||||
orbit.channel(channelName).put("key1", "hello world");
|
||||
orbit.channel(channelName).get("key1"); // returns "hello world"
|
||||
orbit.channel(channelName).remove("key1");
|
||||
|
||||
// Modes
|
||||
/* Modes */
|
||||
const password = 'hello';
|
||||
let channelModes;
|
||||
channelModes = orbit.channel(channel).setMode({ mode: "+r", params: { password: password } }); // { modes: { r: { password: 'hello' } } }
|
||||
@ -94,7 +97,7 @@ async(() => {
|
||||
channelModes = orbit.channel(channel, password).setMode({ mode: "-r" }); // { modes: { ... } }
|
||||
channelModes = orbit.channel(channel, '').setMode({ mode: "-w" }); // { modes: {} }
|
||||
|
||||
// Delete channel
|
||||
/* Delete channel */
|
||||
const result = orbit.channel(channelName, channelPwd).delete(); // true | false
|
||||
})();
|
||||
```
|
||||
|
13
package.json
13
package.json
@ -1,22 +1,23 @@
|
||||
{
|
||||
"name": "orbit-client",
|
||||
"name": "orbit-db",
|
||||
"version": "0.1.1",
|
||||
"description": "Event Log and KeyValue Store on IPFS",
|
||||
"description": "Key-Value Store and Event Log on IPFS",
|
||||
"author": "Haad",
|
||||
"license": "MIT",
|
||||
"engines" : {
|
||||
"node" : "^4.x.x"
|
||||
"engines": {
|
||||
"node": "^4.x.x"
|
||||
},
|
||||
"main": "src/OrbitClient.js",
|
||||
"dependencies": {
|
||||
"asyncawait": "^1.0.1",
|
||||
"bluebird": "^3.1.1",
|
||||
"bs58": "^3.0.0",
|
||||
"ipfsd-ctl": "^0.7.1",
|
||||
"orbit-common": "^0.1.0",
|
||||
"unirest": "^0.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "^2.3.4"
|
||||
"mocha": "^2.3.4",
|
||||
"orbit-server": "^0.1.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var ipfsAPI = require('./ipfs-api-promised');
|
||||
var ipfsAPI = require('orbit-common/lib/ipfs-api-promised');
|
||||
var Keystore = require('orbit-common/lib/Keystore');
|
||||
var Encryption = require('orbit-common/lib/Encryption');
|
||||
var HashCache = require('./HashCacheClient');
|
||||
var HashCacheItem = require('./HashCacheItem').EncryptedHashCacheItem;
|
||||
var HashCacheOps = require('./HashCacheItem').HashCacheOps;
|
||||
var Keystore = require('./Keystore');
|
||||
var Encryption = require('./Encryption');
|
||||
|
||||
var pubkey = Keystore.getKeys().publicKey;
|
||||
var privkey = Keystore.getKeys().privateKey;
|
||||
@ -29,7 +29,7 @@ class Aggregator {
|
||||
|
||||
if(item) {
|
||||
if((item.op === HashCacheOps.Put || item.op === HashCacheOps.Add) && !this._contains(handledItems, item.key)) {
|
||||
if(!opts.key || opts.key && opts.key === item.key) {
|
||||
if(!opts.key || (opts.key && opts.key === item.key)) {
|
||||
res.push({ hash: hash, item: item });
|
||||
currentDepth ++;
|
||||
handledItems.push(item.target);
|
||||
|
@ -1,61 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
|
||||
var algorithm = 'aes-256-ecb';
|
||||
|
||||
class Encryption {
|
||||
static encrypt(text, privkey, pubkey) {
|
||||
var encrypted;
|
||||
try {
|
||||
var cipher = crypto.createCipher(algorithm, privkey)
|
||||
encrypted = cipher.update(text, 'utf8', 'hex')
|
||||
encrypted += cipher.final('hex');
|
||||
} catch(e) {
|
||||
console.log("Error while encrypting:", e, e.stack);
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
static decrypt(text, privkey, pubkey) {
|
||||
var decrypted;
|
||||
try {
|
||||
var cipher = crypto.createDecipher(algorithm, privkey)
|
||||
decrypted = cipher.update(text, 'hex', 'utf8')
|
||||
decrypted += cipher.final('utf8');
|
||||
} catch(e) {
|
||||
console.log("Error while decrypting:", e, e.stack);
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
static hashWithSHA512(data, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var hash = crypto.createHmac('sha512', salt);
|
||||
hash.update(data);
|
||||
var value = hash.digest('hex');
|
||||
return value;
|
||||
}
|
||||
|
||||
static sign(data, privkey, seq, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var sign = crypto.createSign('RSA-SHA256');
|
||||
var hash = Encryption.hashWithSHA512(data, "" + salt)
|
||||
sign.update("" + seq + hash);
|
||||
var sig = sign.sign(privkey, 'hex');
|
||||
return sig;
|
||||
}
|
||||
|
||||
static verify(data, pubkey, sig, seq, salt) {
|
||||
if(!salt) salt = "null";
|
||||
var verify = crypto.createVerify('RSA-SHA256');
|
||||
var hash = Encryption.hashWithSHA512(data, salt);
|
||||
verify.update("" + seq + hash);
|
||||
var verified = verify.verify(pubkey, sig, 'hex');
|
||||
return verified;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Encryption;
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const Encryption = require('./Encryption');
|
||||
const Encryption = require('orbit-common/lib/Encryption');
|
||||
|
||||
const HashCacheOps = {
|
||||
Add: "ADD",
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var ipfsDaemon = require('./ipfs-daemon');
|
||||
var ipfsAPI = require('./ipfs-api-promised');
|
||||
var Keystore = require('orbit-common/lib/Keystore');
|
||||
var Encryption = require('orbit-common/lib/Encryption');
|
||||
var ipfsDaemon = require('orbit-common/lib/ipfs-daemon');
|
||||
var ipfsAPI = require('orbit-common/lib/ipfs-api-promised');
|
||||
var HashCache = require('./HashCacheClient');
|
||||
var HashCacheItem = require('./HashCacheItem').EncryptedHashCacheItem;
|
||||
var HashCacheOps = require('./HashCacheItem').HashCacheOps;
|
||||
@ -11,8 +13,6 @@ var ItemTypes = require('./ItemTypes');
|
||||
var MetaInfo = require('./MetaInfo');
|
||||
var Post = require('./Post');
|
||||
var Aggregator = require('./Aggregator');
|
||||
var Keystore = require('./Keystore');
|
||||
var Encryption = require('./Encryption');
|
||||
|
||||
var pubkey = Keystore.getKeys().publicKey;
|
||||
var privkey = Keystore.getKeys().privateKey;
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var encryption = require('./Encryption');
|
||||
var Encryption = require('orbit-common/lib/Encryption');
|
||||
|
||||
class Post {
|
||||
constructor(content) {
|
||||
@ -9,7 +9,7 @@ class Post {
|
||||
}
|
||||
|
||||
encrypt(privkey, pubkey) {
|
||||
this.content = encryption.encrypt(this.content, privkey, pubkey);
|
||||
this.content = Encryption.encrypt(this.content, privkey, pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,81 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
var ipfsAPI = {
|
||||
cat: (ipfs, hash, cb) => {
|
||||
var ipfscat = Promise.promisify(ipfs.cat);
|
||||
return ipfscat(hash);
|
||||
},
|
||||
ls: async ((ipfs, hash) => {
|
||||
var ipfsls = Promise.promisify(ipfs.ls);
|
||||
return ipfsls(hash);
|
||||
}),
|
||||
add: async ((ipfs, filePath) => {
|
||||
var addFiles = Promise.promisify((filePath, cb) => {
|
||||
ipfs.add(filePath, { recursive: true }, cb);
|
||||
});
|
||||
return addFiles(filePath);
|
||||
}),
|
||||
getObject: async ((ipfs, hash) => {
|
||||
var getObject = Promise.promisify(ipfs.object.get);
|
||||
return getObject(hash);
|
||||
}),
|
||||
putObject: async ((ipfs, payload) => {
|
||||
var putObject = Promise.promisify((payload, cb) => {
|
||||
ipfs.object.put(new Buffer(JSON.stringify({ Data: payload })), "json", cb);
|
||||
});
|
||||
return putObject(payload);
|
||||
}),
|
||||
patchObject: async ((ipfs, root, target) => {
|
||||
var patchObject = Promise.promisify((root, target, cb) => {
|
||||
ipfs.object.patch(root, ["add-link", "next", target], cb);
|
||||
});
|
||||
return patchObject(root, target);
|
||||
}),
|
||||
statObject: async ((ipfs, hash) => {
|
||||
var getObject = Promise.promisify(ipfs.object.stat);
|
||||
return getObject(hash);
|
||||
}),
|
||||
pinObject: async ((ipfs, hash) => {
|
||||
var pinObject = Promise.promisify(ipfs.pin.add);
|
||||
return pinObject(hash);
|
||||
}),
|
||||
getPinned: async ((ipfs) => {
|
||||
var getPinned = Promise.promisify(ipfs.pin.list);
|
||||
var list = await (getPinned());
|
||||
return Object.keys(list.Keys);
|
||||
}),
|
||||
swarmPeers: async ((ipfs) => {
|
||||
var getPeers = Promise.promisify(ipfs.swarm.peers);
|
||||
return getPeers();
|
||||
}),
|
||||
swarmConnect: async ((ipfs, hash) => {
|
||||
var connect = Promise.promisify(ipfs.swarm.connect);
|
||||
return await (connect(hash));
|
||||
}),
|
||||
dhtPut: async ((ipfs, key, value) => {
|
||||
var put = Promise.promisify(ipfs.dht.put);
|
||||
return put(key, value);
|
||||
}),
|
||||
dhtGet: async ((ipfs, key) => {
|
||||
var get = Promise.promisify(ipfs.dht.get);
|
||||
return get(key);
|
||||
}),
|
||||
dhtQuery: async ((ipfs, peerID) => {
|
||||
var query = Promise.promisify(ipfs.dht.query);
|
||||
return query(peerID);
|
||||
}),
|
||||
dhtFindProviders: async ((ipfs, hash) => {
|
||||
var findprov = Promise.promisify(ipfs.dht.findprovs);
|
||||
return findprov(hash);
|
||||
}),
|
||||
dhtFindPeer: async ((ipfs, peerID) => {
|
||||
var findpeer = Promise.promisify(ipfs.dht.findpeer);
|
||||
return findpeer(peerID);
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = ipfsAPI;
|
@ -1,39 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var Promise = require('bluebird');
|
||||
var ipfsdCtl = require('ipfsd-ctl');
|
||||
|
||||
const getUserHome = () => {
|
||||
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||
};
|
||||
|
||||
const ipfsPath = path.resolve(getUserHome() + '/.ipfs');
|
||||
|
||||
if(!fs.existsSync(ipfsPath))
|
||||
fs.mkdirSync(ipfsPath);
|
||||
|
||||
const startIpfs = async (() => {
|
||||
let ipfs, nodeInfo;
|
||||
|
||||
try {
|
||||
const ipfsNode = Promise.promisify(ipfsdCtl.local.bind(ipfsPath))
|
||||
const ipfsd = await (ipfsNode());
|
||||
const start = Promise.promisify(ipfsd.startDaemon.bind(ipfsd));
|
||||
ipfs = await (start());
|
||||
const getId = Promise.promisify(ipfs.id);
|
||||
nodeInfo = await (getId())
|
||||
} catch(e) {
|
||||
console.log("Error initializing ipfs daemon:", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return { daemon: ipfs, nodeInfo: nodeInfo };
|
||||
});
|
||||
|
||||
module.exports = async(() => {
|
||||
return await(startIpfs());
|
||||
});
|
@ -1,78 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var assert = require('assert');
|
||||
var async = require('asyncawait/async');
|
||||
var await = require('asyncawait/await');
|
||||
var encryption = require('../src/Encryption');
|
||||
var ipfsDaemon = require('orbit-common/lib/ipfs-daemon');
|
||||
var logger = require('orbit-common/lib/logger');
|
||||
var Server = require('orbit-server/src/server');
|
||||
var OrbitClient = require('../src/OrbitClient');
|
||||
|
||||
// var mockServerAddresses = [
|
||||
// "localhost",
|
||||
// "127.0.0.1"
|
||||
// ];
|
||||
|
||||
// var serverConfig = {
|
||||
// networkId: "anon-test",
|
||||
// networkName: "Anonymous Networks TEST",
|
||||
// salt: "thisisthenetworksalt",
|
||||
// userDataPath: path.resolve("/tmp/anon-server-tests"),
|
||||
// verifyMessages: true
|
||||
// }
|
||||
|
||||
// Create the userDataPath in case it doesn't exist
|
||||
// if(!fs.existsSync(serverConfig.userDataPath))
|
||||
// fs.mkdirSync(serverConfig.userDataPath);
|
||||
var serverConfig = {
|
||||
networkId: "orbitdb-test",
|
||||
networkName: "OrbitDB Test Network",
|
||||
salt: "hellothisisdog",
|
||||
userDataPath: "/tmp/orbitdb-tests",
|
||||
verifyMessages: true
|
||||
}
|
||||
|
||||
// Orbit
|
||||
var host = 'localhost:3006';
|
||||
var username = 'testrunner';
|
||||
var password = '';
|
||||
const host = 'localhost';
|
||||
const port = 3006;
|
||||
const username = 'testrunner';
|
||||
const password = '';
|
||||
|
||||
const startServer = async (() => {
|
||||
// TODO: this should be handled by orbit-server
|
||||
if(!fs.existsSync(serverConfig.userDataPath))
|
||||
fs.mkdirSync(serverConfig.userDataPath);
|
||||
|
||||
return new Promise(async((resolve, reject) => {
|
||||
logger.setLevel('ERROR');
|
||||
const ipfsd = await(ipfsDaemon());
|
||||
const server = Server(ipfsd.daemon, ipfsd.nodeInfo, serverConfig);
|
||||
server.app.listen(port, () => {
|
||||
resolve(server);
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('Orbit Client', () => {
|
||||
// let ipfs, server, orbit, httpServer;
|
||||
let orbit;
|
||||
let server, orbit;
|
||||
|
||||
let head = '';
|
||||
let second = '';
|
||||
let items = [];
|
||||
let head = '';
|
||||
let items = [];
|
||||
let channel = 'abcdefgh';
|
||||
|
||||
before(function(done) {
|
||||
// logger.setLevel('ERROR');
|
||||
// Start ipfs daemon
|
||||
// if(!ipfs && !server) {
|
||||
// var startIpfsDaemon = new Promise(async((resolve, reject) => {
|
||||
// ipfs = await(ipfsd());
|
||||
// ipfs.nodeInfo.Addresses = mockServerAddresses;
|
||||
// // Start hash-cache server
|
||||
// server = require('../../ipfs-backend/server/server')(ipfs.daemon, ipfs.nodeInfo, serverConfig);
|
||||
// httpServer = server.app.listen(3006, async(() => {
|
||||
// logger.info('network server listening at http://localhost:%s', 3006);
|
||||
// orbit = await(OrbitClient.connect(host, username, password, ipfs.daemon));
|
||||
// resolve();
|
||||
// }));
|
||||
// }));
|
||||
// startIpfsDaemon.then(done);
|
||||
// } else {
|
||||
// done();
|
||||
// }
|
||||
var start = () => new Promise(async((resolve, reject) => {
|
||||
orbit = OrbitClient.connect(host, username, password);
|
||||
before(async((done) => {
|
||||
var initialize = () => new Promise(async((resolve, reject) => {
|
||||
orbit = OrbitClient.connect(`${host}:${port}`, username, password);
|
||||
orbit.channel(channel, '').delete();
|
||||
resolve();
|
||||
}));
|
||||
start().then(done);
|
||||
});
|
||||
server = await(startServer());
|
||||
await(initialize());
|
||||
done();
|
||||
}));
|
||||
|
||||
after(function(done) {
|
||||
var deleteChannel = () => new Promise(async((resolve, reject) => {
|
||||
orbit.channel(channel, '').delete();
|
||||
if(orbit) orbit.channel(channel, '').delete();
|
||||
resolve();
|
||||
}));
|
||||
deleteChannel().then(done);
|
||||
// server.shutdown();
|
||||
// httpServer.close();
|
||||
// rmDir(serverConfig.userDataPath);
|
||||
server.shutdown();
|
||||
});
|
||||
|
||||
/* TESTS */
|
||||
@ -80,9 +71,9 @@ describe('Orbit Client', () => {
|
||||
it('connects to hash-cache-server', async((done) => {
|
||||
assert.notEqual(orbit, null);
|
||||
assert.notEqual(orbit.client, null);
|
||||
assert.equal(orbit.user.id, 'QmcLzfQBKuvBYLsmgt4nkaUM7i7LNL37dPtnBZWgGpjPRW');
|
||||
assert.equal(orbit.network.id, 'anon-test');
|
||||
assert.equal(orbit.network.name, 'Anonymous Networks TEST');
|
||||
assert.equal(orbit.user.id, 'Qmf5A5RSTQmcfvigT3j29Fqh2fAHRANk5ooBYKdWsPtr8U');
|
||||
assert.equal(orbit.network.id, serverConfig.networkId);
|
||||
assert.equal(orbit.network.name, serverConfig.networkName);
|
||||
assert.notEqual(orbit.network.config.SupernodeRouting, null);
|
||||
assert.notEqual(orbit.network.config.Bootstrap.length, 0);
|
||||
done();
|
||||
@ -158,7 +149,7 @@ describe('Orbit Client', () => {
|
||||
it('adds an item to an empty channel', async((done) => {
|
||||
try {
|
||||
orbit.channel(channel, '').delete();
|
||||
head = orbit.channel(channel, '').add('hello');
|
||||
const head = orbit.channel(channel, '').add('hello');
|
||||
assert.notEqual(head, null);
|
||||
assert.equal(head.startsWith('Qm'), true);
|
||||
assert.equal(head.length, 46);
|
||||
@ -170,8 +161,8 @@ describe('Orbit Client', () => {
|
||||
|
||||
it('adds a new item to a channel with one item', async((done) => {
|
||||
try {
|
||||
var v = orbit.channel(channel, '').iterator().collect();
|
||||
second = orbit.channel(channel, '').add('hello');
|
||||
const head = orbit.channel(channel, '').iterator().collect()[0];
|
||||
const second = orbit.channel(channel, '').add('hello');
|
||||
assert.notEqual(second, null);
|
||||
assert.notEqual(second, head);
|
||||
assert.equal(second.startsWith('Qm'), true);
|
||||
@ -585,17 +576,3 @@ describe('Orbit Client', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// let rmDir = function(dirPath) {
|
||||
// try { var files = fs.readdirSync(dirPath); }
|
||||
// catch(e) { return; }
|
||||
// if (files.length > 0)
|
||||
// for (var i = 0; i < files.length; i++) {
|
||||
// var filePath = dirPath + '/' + files[i];
|
||||
// if (fs.statSync(filePath).isFile())
|
||||
// fs.unlinkSync(filePath);
|
||||
// else
|
||||
// rmDir(filePath);
|
||||
// }
|
||||
// fs.rmdirSync(dirPath);
|
||||
// };
|
||||
|
Loading…
x
Reference in New Issue
Block a user