diff --git a/src/js/gun.js b/src/js/gun.js index 8c56cf2b..1a125c11 100644 --- a/src/js/gun.js +++ b/src/js/gun.js @@ -50,6 +50,17 @@ if(u !== o['<'] && t <= o['<']){ return true } return false; } + Type.text.hash = function(s, c){ // via SO + if(typeof s !== 'string'){ return } + c = c || 0; + if(!s.length){ return c } + for(var i=0,l=s.length,n; i MD? MD : to); // setTimeout Max Defer 32bit :( - if(!ctx.to){ root.on('in', {'@': msg['#'], err: to}) } ctx.to = 1; + if(!ctx.to){ root.on('in', {'@': msg['#'], err: to}) } ctx.to = 1; // TODO: This causes too many problems unless sending peers auto-retry. return to; } - return; + //return; // it should be this + if(!ctx.miss){ return } // but some chains have a cache miss that need to re-fire. // TODO: Improve in future. } (lot = ctx.lot||'').s++; lot.more++; (ctx.stun || (ctx.stun = {}))[soul+key] = 1; @@ -784,7 +796,7 @@ if((tmp = ctx.out) && (tmp = tmp.put)){ tmp[soul] = state_ify(tmp[soul], key, state, val, soul); // TODO: Hacky, fix & come back later, for actual pushing messages. } - if(!(--ctx.lot.more)){ fire(ctx) } + if(!(--ctx.lot.more)){ fire(ctx) } // TODO: 'forget' feature in SEA tied to this, bad approach, but hacked in for now. Any changes here must update there. eve.to.next(msg); } function chain(ctx, soul, key,val, state){ @@ -797,7 +809,7 @@ function fire(ctx){ if(ctx.err){ return } var stop = {}; - var root = ctx.root, next = root.next||'', put = ctx.put, tmp; + var root = ((ctx.$||'')._||'').root, next = (root||'').next||'', put = ctx.put, tmp; var S = +new Date; //Gun.graph.is(put, function(node, soul){ for(var soul in put){ var node = put[soul]; // Gun.obj.native() makes this safe. @@ -920,6 +932,7 @@ node = Gun.graph.node(node); tmp = (at||empty).ack; var faith = function(){}; faith.ram = faith.faith = true; // HNPERF: We're testing performance improvement by skipping going through security again, but this should be audited. + faith.$ = msg.$; DBG && (DBG.ga = +new Date); root.on('in', { '@': msg['#'], @@ -956,7 +969,7 @@ obj_map(v, each, this[k]); }, at.opt); Gun.on('opt', at); - at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) } + //at.opt.uuid = at.opt.uuid || function(){ return state_lex() + text_rand(12) } Gun.obj.native(); return gun; } @@ -976,7 +989,7 @@ if(typeof window !== "undefined"){ (window.GUN = window.Gun = Gun).window = window } try{ if(typeof MODULE !== "undefined"){ MODULE.exports = Gun } }catch(e){} module.exports = Gun; - + (Gun.window||'').console = (Gun.window||'').console || {log: function(){}}; (C = console).only = function(i, s){ return (C.only.i && i === C.only.i && C.only.i++) && (C.log.apply(C, arguments) || s) }; @@ -1320,6 +1333,9 @@ at.on('in', {get: at.get, put: Gun.val.link.ify(get['#']), $: at.$, '@': msg['@']}); return; } + if(at.$ === (msg._||'').$){ // replying to self, for perf, skip ham/security tho needs audit. + (msg._).miss = (at.put === u); + } Gun.on.put(msg); } var empty = {}, u; @@ -1402,7 +1418,7 @@ if(cat.jam){ return cat.jam.push([cb, as]) } cat.jam = [[cb,as]]; gun.get(function go(msg, eve){ - if(u === msg.put && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks < tmp){ + if(u === msg.put && !cat.root.opt.super && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks <= tmp){ // TODO: super should not be in core code, bring AXE up into core instead to fix? return; } eve.rid(msg); @@ -1489,6 +1505,7 @@ return gun; } as.soul = as.soul || (as.not = Gun.node.soul(as.data) || (as.via.back('opt.uuid') || Gun.text.random)()); + as.via._.stun = {}; if(!as.soul){ // polyfill async uuid for SEA as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback if(err){ return Gun.log(err) } // TODO: Handle error! @@ -1501,9 +1518,11 @@ ify(as); return gun; } + as.via._.stun = {}; if(Gun.is(data)){ data.get(function(soul, o, msg){ if(!soul){ + delete as.via._.stun; return Gun.log("The reference you are saving is a", typeof msg.put, '"'+ msg.put +'", not a node (object)!'); } gun.put(Gun.val.link.ify(soul), cb, as); @@ -1567,6 +1586,7 @@ if(!as.graph || !obj_empty(as.stun)){ return } as.res = as.res || function(cb){ if(cb){ cb() } }; as.res(function(){ + delete as.via._.stun; var cat = (as.$.back(-1)._), ask = cat.ask(function(ack){ cat.root.on('ack', ack); if(ack.err){ Gun.log(ack) } @@ -1587,6 +1607,7 @@ }); cat.root.mum = mum? obj.to(mum, cat.root.mum) : mum; cat.root.now = tmp; + as.via._.on('res', {}); delete as.via._.tag.res; // emitting causes mem leak? }, as); if(as.res){ as.res() } } function no(v,k){ if(v){ return true } } @@ -1609,15 +1630,22 @@ return; } (as.stun = as.stun || {})[path] = 1; - ref.get(soul, true, {as: {at: at, as: as, p:path}}); + ref.get(soul, true, {as: {at: at, as: as, p:path, ref: ref}}); }, {as: as, at: at}); //if(is){ return {} } } - + var G = String.fromCharCode(31); function soul(id, as, msg, eve){ - var as = as.as, cat = as.at; as = as.as; + var as = as.as, path = as.p, ref = as.ref, cat = as.at, pat = []; as = as.as; + ref.back(function(at){ + if(sat = at.soul || at.link || at.dub){ return sat } + pat.push(at.has || at.get); + }); + pat = [sat || as.soul].concat(pat.reverse()); var at = ((msg || {}).$ || {})._ || {}; - id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || (as.via.back('opt.uuid') || Gun.text.random)(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous? + id = at.dub = at.dub || id || Gun.node.soul(cat.obj) || Gun.node.soul(msg.put || at.put) || Gun.val.link.is(msg.put || at.put) || pat.join('/') /* || (function(){ + return (as.soul+'.')+Gun.text.hash(path.join(G)).toString(32); + })(); // TODO: BUG!? Do we really want the soul of the object given to us? Could that be dangerous? What about copy operations? */ if(eve){ eve.stun = true } if(!id){ // polyfill async uuid for SEA as.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback @@ -1649,6 +1677,7 @@ if(as.ref !== as.$){ tmp = (as.$._).get || at.get; if(!tmp){ // TODO: Handle + delete as.via._.stun; Gun.log("Please report this as an issue! Put.no.get"); // TODO: BUG!?? return; } @@ -1656,7 +1685,7 @@ tmp = null; } if(u === data){ - if(!at.get){ return } // TODO: Handle + if(!at.get){ delete as.via._.stun; return } // TODO: Handle if(!soul){ tmp = at.$.back(function(at){ if(at.link || at.soul){ return at.link || at.soul } @@ -1681,7 +1710,7 @@ } if(!as.soul){ // polyfill async uuid for SEA as.via.back('opt.uuid')(function(err, soul){ // TODO: improve perf without anonymous callback - if(err){ return Gun.log(err) } // Handle error. + if(err){ delete as.via._.stun; return Gun.log(err) } // Handle error. as.ref.put(as.data, as.soul = soul, as); }); return; @@ -1790,9 +1819,10 @@ } if((tmp = eve.wait) && (tmp = tmp[at.id])){ clearTimeout(tmp) } eve.ack = (eve.ack||0)+1; - if(!to && u === data && eve.ack <= (opt.acks || Object.keys(at.root.opt.peers).length)){ return } + // TODO: super should not be in core code, bring AXE up into core instead to fix? + if(!to && u === data && !at.root.opt.super && eve.ack <= (opt.acks || Object.keys(at.root.opt.peers).length)){ return } if((!to && (u === data || at.soul || at.link || (link && !(0 < link.ack)))) - || (u === data && (tmp = Object.keys(at.root.opt.peers).length) && (!to && (link||at).ack < tmp))){ + || (u === data && !at.root.opt.super && (tmp = Object.keys(at.root.opt.peers).length) && (!to && (link||at).ack < tmp))){ tmp = (eve.wait = {})[at.id] = setTimeout(function(){ val.call({as:opt}, msg, eve, tmp || 1); }, opt.wait || 99); @@ -1890,17 +1920,20 @@ opt = opt || {}; opt.item = opt.item || item; if(soul = Gun.node.soul(item)){ item = Gun.obj.put({}, soul, Gun.val.link.ify(soul)) } if(!Gun.is(item)){ - if(Gun.obj.is(item)){; - item = gun.back(-1).get(soul = soul || Gun.node.soul(item) || gun.back('opt.uuid')()).put(item); + if(Gun.obj.is(item)){ + //item = gun.back(-1).get(soul = soul || Gun.node.soul(item) || (gun.back('opt.uuid') || uuid)()).put(item); + soul = soul || Gun.node.soul(item) || uuid(); // this just key now, not a soul. } - return gun.get(soul || (Gun.state.lex() + Gun.text.random(7))).put(item, cb, opt); + return gun.get(soul || uuid()).put(item, cb, opt); } item.get(function(soul, o, msg){ + if(!soul && item._.stun){ item._.on('res', function(){ this.off(); gun.set(item, cb, opt) }); return } if(!soul){ return cb.call(gun, {err: Gun.log('Only a node can be linked! Not "' + msg.put + '"!')}) } gun.put(Gun.obj.put({}, soul, Gun.val.link.ify(soul)), cb, opt); },true); return item; } + function uuid(){ return Gun.state.lex() + Gun.text.random(7) } })(USE, './set'); ;USE(function(module){ @@ -2133,10 +2166,10 @@ var SMIA = 0; var message, loop; function each(peer){ mesh.say(message, peer) } - var say = mesh.say = function(msg, peer){ - if(this.to){ this.to.next(msg) } // compatible with middleware adapters. + var say = mesh.say = function(msg, peer){ var tmp; + if((tmp = this) && (tmp = tmp.to) && tmp.next){ tmp.next(msg) } // compatible with middleware adapters. if(!msg){ return false } - var id, hash, tmp, raw; + var id, hash, raw; var DBG = msg.DBG, S; if(!peer){ S = +new Date ; DBG && (DBG.y = S) } var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } @@ -2300,7 +2333,7 @@ }); root.on('bye', function(peer, tmp){ - peer = opt.peers[peer.id || peer] || peer; + peer = opt.peers[peer.id || peer] || peer; this.to.next(peer); peer.bye? peer.bye() : (tmp = peer.wire) && tmp.close && tmp.close(); Type.obj.del(opt.peers, peer.id); @@ -2325,18 +2358,6 @@ } ;(function(){ - Type.text.hash = function(s){ // via SO - if(typeof s !== 'string'){ return {err: 1} } - var c = 0; - if(!s.length){ return c } - for(var i=0,l=s.length,n; i Buffer.from(crypto.randomBytes(len)) }); - const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); - api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH - } - catch(e){ - console.log("text-encoding and peculiar/nwebcrypto may not be included by default, please add it to your package.json!"); + const isocrypto = require('isomorphic-webcrypto'); + api.ossl = api.subtle = isocrypto.subtle; + }catch(e){ + console.log("text-encoding and @peculiar/webcrypto may not be included by default, please add it to your package.json!"); + TEXT_ENCODING_OR_PECULIAR_WEBCRYPTO_NOT_INSTALLED; }} module.exports = api @@ -710,10 +707,9 @@ ;USE(function(module){ var Gun = USE('./sea').Gun; - Gun.chain.then = function(cb, opt = {}){ - opt = {wait: 200, ...opt} + Gun.chain.then = function(cb){ var gun = this, p = (new Promise(function(res, rej){ - gun.once(res, opt); + gun.once(res); })); return cb? p.then(cb) : p; } @@ -741,7 +737,7 @@ at.opt.uuid = function(cb){ var id = uuid(), pub = root.user; if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id } - id = id + '~' + pub + '.'; + id = id + '~' + pub + '/'; if(cb && cb.call){ cb(null, id) } return id; } @@ -1087,43 +1083,6 @@ }()); return gun; } - - /** - * returns the decrypted value, encrypted by secret - * @returns {Promise} - */ - User.prototype.decrypt = function(cb) { - let gun = this, - path = '' - gun.back(function(at) { - if (at.is) { - return - } - path += at.get || '' - }) - return gun - .then(async data => { - if (data == null) { - return - } - const user = gun.back(-1).user() - const pair = user.pair() - let sec = await user - .get('trust') - .get(pair.pub) - .get(path) - sec = await SEA.decrypt(sec, pair) - if (!sec) { - return data - } - let decrypted = await SEA.decrypt(data, sec) - return decrypted - }) - .then(res => { - cb && cb(res) - return res - }) - } module.exports = User })(USE, './create'); @@ -1190,6 +1149,7 @@ var u; function check(msg){ // REVISE / IMPROVE, NO NEED TO PASS MSG/EVE EACH SUB? var eve = this, at = eve.as, put = msg.put, soul = put['#'], key = put['.'], val = put[':'], state = put['>'], id = msg['#'], tmp; + if(!soul || !key){ return } if((msg._||'').faith && (at.opt||'').faith && 'function' == typeof msg._){ SEA.verify(SEA.opt.pack(put), false, function(data){ // this is synchronous if false put['='] = SEA.opt.unpack(data); @@ -1200,8 +1160,13 @@ var no = function(why){ at.on('in', {'@': id, err: why}) }; //var no = function(why){ msg.ack(why) }; (msg._||'').DBG && ((msg._||'').DBG.c = +new Date); - if('#' === soul[0]){ // special case for content addressing immutable hashed data. - check.hash(eve, msg, val, key, soul, at, no); return; + if(0 <= soul.indexOf(' s.length){ return } - if('@' === (s[0]||'')[0]){ return } // TODO: Should check ~X.Y. are alphanumeric, not just not @. + s = s.split(pubcut).slice(0,2); + if(!s || 2 != s.length){ return } + if('@' === (s[0]||'')[0]){ return } s = s.slice(0,2).join('.'); return s; } diff --git a/src/js/store.js b/src/js/store.js index 672f8010..a4af2ad9 100644 --- a/src/js/store.js +++ b/src/js/store.js @@ -8,7 +8,7 @@ Gun.on('create', function(root){ var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; var ST = 0; - + // TODO: BUG! For RN storage, RN does not like the following require: opt.store = opt.store || (!Gun.window && require('./rfs')(opt)); var dare = Radisk(opt), esc = String.fromCharCode(27);