| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- const crypto = require('crypto');
- const pull = require('../../src/server/node_modules/pull-stream');
- const ssbKeys = require('../../src/server/node_modules/ssb-keys');
- let pullPushable;
- try {
- pullPushable = require('../../src/server/node_modules/pull-pushable');
- } catch (_) {
- try { pullPushable = require('../../src/server/node_modules/@krakenslab/pull-pushable'); } catch (__) {}
- }
- const generateMsgKey = () => '%' + crypto.randomBytes(32).toString('base64').replace(/=+$/, '') + '.sha256';
- function makeNetwork() {
- const log = [];
- const liveListeners = new Set();
- return {
- log,
- publish(msg) {
- log.push(msg);
- for (const cb of liveListeners) {
- try { cb(msg); } catch (_) {}
- }
- },
- listen(cb) {
- liveListeners.add(cb);
- return () => liveListeners.delete(cb);
- },
- reset() {
- log.length = 0;
- liveListeners.clear();
- }
- };
- }
- function makeNode(network, keypair, opts = {}) {
- const seqByAuthor = new Map();
- const node = {
- id: keypair.id,
- keys: keypair,
- publish(content, cb) {
- let actualContent = content;
- if (content && typeof content === 'object' && Array.isArray(content.recps) && content.recps.length) {
- try {
- actualContent = ssbKeys.box(content, content.recps);
- } catch (e) {
- if (cb) cb(e);
- return;
- }
- }
- const key = generateMsgKey();
- const prev = seqByAuthor.get(keypair.id) || 0;
- const sequence = prev + 1;
- seqByAuthor.set(keypair.id, sequence);
- const ts = Date.now();
- const msg = {
- key,
- value: {
- previous: null,
- sequence,
- author: keypair.id,
- timestamp: ts,
- hash: 'sha256',
- content: actualContent,
- signature: 'mock-sig'
- },
- timestamp: ts
- };
- network.publish(msg);
- if (cb) cb(null, { key, value: msg.value });
- },
- createLogStream(opt = {}) {
- const { limit, reverse, live, old } = opt;
- const items = network.log.slice();
- const baseItems = old !== false ? items : [];
- let prepared = baseItems;
- if (reverse) prepared = prepared.slice().reverse();
- if (limit) prepared = prepared.slice(0, limit);
- if (!live) return pull.values(prepared);
- if (!pullPushable) {
- const initial = pull.values(prepared);
- return initial;
- }
- const p = pullPushable();
- for (const m of prepared) p.push(m);
- const off = network.listen(m => p.push(m));
- const origAbort = p.end;
- p.end = (err) => { off(); if (origAbort) origAbort.call(p, err); };
- return p;
- },
- createUserStream(opt = {}) {
- const { id, reverse, limit } = opt;
- let items = network.log.filter(m => m.value && m.value.author === id);
- if (reverse) items = items.slice().reverse();
- if (limit) items = items.slice(0, limit);
- return pull.values(items);
- },
- get(key, cb) {
- const m = network.log.find(x => x.key === key);
- if (!m) return cb(new Error('not found'));
- cb(null, m.value);
- },
- private: {
- publish(content, recps, cb) {
- let actualContent;
- try {
- actualContent = ssbKeys.box(content, recps);
- } catch (e) { if (cb) cb(e); return; }
- const key = generateMsgKey();
- const prev = seqByAuthor.get(keypair.id) || 0;
- const sequence = prev + 1;
- seqByAuthor.set(keypair.id, sequence);
- const ts = Date.now();
- const msg = { key, value: { previous: null, sequence, author: keypair.id, timestamp: ts, hash: 'sha256', content: actualContent, signature: 'mock-sig' }, timestamp: ts };
- network.publish(msg);
- if (cb) cb(null, { key, value: msg.value });
- },
- unbox(arg) {
- const c = arg && arg.value ? arg.value.content : arg;
- if (typeof c !== 'string' || !c.endsWith('.box')) return null;
- try {
- const decoded = ssbKeys.unbox(c, keypair);
- if (!decoded) return null;
- if (arg && arg.value) {
- return { key: arg.key, value: { ...arg.value, content: decoded }, timestamp: arg.timestamp };
- }
- return decoded;
- } catch (_) { return null; }
- }
- },
- blobs: { has(_url, cb) { cb(null, true); } },
- conn: { hub() { return { listen: () => null }; } },
- replicate: { upto(cb) { if (cb) cb(null, {}); } },
- whoami(cb) { cb(null, { id: keypair.id }); },
- links(opts = {}) {
- const out = [];
- for (const m of network.log) {
- const c = m.value && m.value.content;
- if (!c) continue;
- if (opts.dest && c.target !== opts.dest && c.root !== opts.dest && (!c.branch || (Array.isArray(c.branch) ? !c.branch.includes(opts.dest) : c.branch !== opts.dest))) continue;
- if (opts.rel === 'target' && c.target !== opts.dest) continue;
- if (opts.values) out.push(m);
- else out.push({ source: m.value.author, dest: opts.dest, key: m.key });
- }
- return pull.values(out);
- },
- messagesByType(opts = {}) {
- const wantedType = typeof opts === 'string' ? opts : opts.type;
- const items = network.log.filter(m => {
- const c = m.value && m.value.content;
- return c && typeof c === 'object' && c.type === wantedType;
- });
- return pull.values(items);
- }
- };
- return node;
- }
- function makeCooler(node) {
- return { open: async () => node };
- }
- function generateKeypair() {
- return ssbKeys.generate();
- }
- module.exports = { makeNetwork, makeNode, makeCooler, generateKeypair };
|