From 597bb77a988e1b9820abc527f5747da6b9a7dc4f Mon Sep 17 00:00:00 2001 From: sirpy Date: Thu, 29 Aug 2019 10:54:02 +0300 Subject: [PATCH 01/19] fix: Object.assign modiifies S.ecdh which should be static --- sea/secret.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sea/secret.js b/sea/secret.js index 4009ee31..b52a6fc6 100644 --- a/sea/secret.js +++ b/sea/secret.js @@ -13,7 +13,7 @@ var epriv = pair.epriv; var ecdhSubtle = shim.ossl || shim.subtle; var pubKeyData = keysToEcdhJwk(pub); - var props = Object.assign(S.ecdh, { public: await ecdhSubtle.importKey(...pubKeyData, true, []) }); + var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },S.ecdh); var privKeyData = keysToEcdhJwk(epub, epriv); var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']).then(async (privKey) => { // privateKey scope doesn't leak out from here! @@ -47,4 +47,4 @@ } module.exports = SEA.secret; - \ No newline at end of file + From 1101c0613019c420cf9aa9ff87a057e2ed288aeb Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 29 Aug 2019 14:28:08 -0700 Subject: [PATCH 02/19] this screwed up RAD folders, undo --- lib/stats.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/stats.js b/lib/stats.js index 7b4956ef..42369af3 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -19,7 +19,6 @@ Gun.on('opt', function(root){ os.loadavg = os.loadavg || noop; os.cpus = os.cpus || noop; setTimeout(function(){ - root.opt.file += (process.argv[2]||''); root.stats = Gun.obj.ify((fs.existsSync(__dirname+'/../stats.'+root.opt.file) && fs.readFileSync(__dirname+'/../stats.'+root.opt.file).toString())) || {}; root.stats.up = root.stats.up || {}; root.stats.up.start = root.stats.up.start || +(new Date); From 0515403716aabe56ba7cab69b3813b715a458497 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 29 Aug 2019 14:28:43 -0700 Subject: [PATCH 03/19] use @Artoria2e5 's gold --- examples/style.css | 48 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/style.css b/examples/style.css index bc059405..6c12060d 100644 --- a/examples/style.css +++ b/examples/style.css @@ -135,7 +135,7 @@ ul, li { .red { background: #ea3224; } .green { background: #33cc33; } .blue { background: #4D79D8; } -.yellow { background: #f2b919; } +.yellow { background: #d3a438; } .black { background: black; } .white { background: white; } @@ -145,7 +145,7 @@ ul, li { .redt { color: #ea3224; } .greent { color: #33cc33; } .bluet { color: #4D79D8; } -.yellowt { color: #f2b919; } +.yellowt { color: #d3a438; } .blackt { color: black; } .whitet { color: white; } @@ -156,13 +156,13 @@ ul, li { } @keyframes hue { 0% {background-color: #4D79D8;} 25% {background-color: #33cc33;} - 50% {background-color: #f2b919;} + 50% {background-color: #d3a438;} 75% {background-color: #ea3224;} 100% {background-color: #4D79D8;} } @-webkit-keyframes hue { 0% {background-color: #4D79D8;} 25% {background-color: #33cc33;} - 50% {background-color: #f2b919;} + 50% {background-color: #d3a438;} 75% {background-color: #ea3224;} 100% {background-color: #4D79D8;} } @@ -174,13 +174,13 @@ ul, li { } @keyframes huet { 0% {color: #4D79D8;} 25% {color: #33cc33;} - 50% {color: #f2b919;} + 50% {color: #d3a438;} 75% {color: #ea3224;} 100% {color: #4D79D8;} } @-webkit-keyframes huet { 0% {color: #4D79D8;} 25% {color: #33cc33;} - 50% {color: #f2b919;} + 50% {color: #d3a438;} 75% {color: #ea3224;} 100% {color: #4D79D8;} } @@ -193,13 +193,13 @@ ul, li { 0% {background-color: #ea3224;} 25% {background-color: #4D79D8;} 50% {background-color: #33cc33;} - 75% {background-color: #f2b919;} + 75% {background-color: #d3a438;} 100% {background-color: #ea3224;} } @-webkit-keyframes hue2 { 0% {background-color: #ea3224;} 25% {background-color: #4D79D8;} 50% {background-color: #33cc33;} - 75% {background-color: #f2b919;} + 75% {background-color: #d3a438;} 100% {background-color: #ea3224;} } @@ -211,13 +211,13 @@ ul, li { 0% {color: #ea3224;} 25% {color: #4D79D8;} 50% {color: #33cc33;} - 75% {color: #f2b919;} + 75% {color: #d3a438;} 100% {color: #ea3224;} } @-webkit-keyframes huet2 { 0% {color: #ea3224;} 25% {color: #4D79D8;} 50% {color: #33cc33;} - 75% {color: #f2b919;} + 75% {color: #d3a438;} 100% {color: #ea3224;} } @@ -227,13 +227,13 @@ ul, li { animation: hue3 900s infinite; } @keyframes hue3 { 0% {background-color: #33cc33;} - 25% {background-color: #f2b919;} + 25% {background-color: #d3a438;} 50% {background-color: #ea3224;} 75% {background-color: #4D79D8;} 100% {background-color: #33cc33;} } @-webkit-keyframes hue3 { 0% {background-color: #33cc33;} - 25% {background-color: #f2b919;} + 25% {background-color: #d3a438;} 50% {background-color: #ea3224;} 75% {background-color: #4D79D8;} 100% {background-color: #33cc33;} @@ -245,52 +245,52 @@ ul, li { animation: huet3 900s infinite; } @keyframes huet3 { 0% {color: #33cc33;} - 25% {color: #f2b919;} + 25% {color: #d3a438;} 50% {color: #ea3224;} 75% {color: #4D79D8;} 100% {color: #33cc33;} } @-webkit-keyframes huet3 { 0% {color: #33cc33;} - 25% {color: #f2b919;} + 25% {color: #d3a438;} 50% {color: #ea3224;} 75% {color: #4D79D8;} 100% {color: #33cc33;} } .hue4 { - background: #f2b919; + background: #d3a438; -webkit-animation: hue4 900s infinite; animation: hue4 900s infinite; } @keyframes hue4 { - 0% {background-color: #f2b919;} + 0% {background-color: #d3a438;} 25% {background-color: #ea3224;} 50% {background-color: #4D79D8;} 75% {background-color: #33cc33;} - 100% {background-color: #f2b919;} + 100% {background-color: #d3a438;} } @-webkit-keyframes hue4 { - 0% {background-color: #f2b919;} + 0% {background-color: #d3a438;} 25% {background-color: #ea3224;} 50% {background-color: #4D79D8;} 75% {background-color: #33cc33;} - 100% {background-color: #f2b919;} + 100% {background-color: #d3a438;} } .huet4 { - color: #f2b919; + color: #d3a438; -webkit-animation: huet4 900s infinite; animation: huet4 900s infinite; } @keyframes huet4 { - 0% {color: #f2b919;} + 0% {color: #d3a438;} 25% {color: #ea3224;} 50% {color: #4D79D8;} 75% {color: #33cc33;} - 100% {color: #f2b919;} + 100% {color: #d3a438;} } @-webkit-keyframes huet4 { - 0% {color: #f2b919;} + 0% {color: #d3a438;} 25% {color: #ea3224;} 50% {color: #4D79D8;} 75% {color: #33cc33;} - 100% {color: #f2b919;} + 100% {color: #d3a438;} } .pulse { From aa558f07066447662a091856c1a687afad85efdf Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 29 Aug 2019 14:29:08 -0700 Subject: [PATCH 04/19] don't crash if multicast offline --- lib/multicast.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/multicast.js b/lib/multicast.js index bcfd2185..75ebb9a0 100644 --- a/lib/multicast.js +++ b/lib/multicast.js @@ -22,7 +22,7 @@ Gun.on('create', function(root){ socket.bind(udp.port); socket.on("listening", function(){ - socket.addMembership(udp.address); + try { socket.addMembership(udp.address) }catch(e){ return } udp.peer = {id: udp.address + ':' + udp.port, wire: socket}; udp.peer.say = function(raw){ From a34e90e86872c4d3f291a3b3ec86c6f26df9fce4 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Thu, 29 Aug 2019 14:43:47 -0700 Subject: [PATCH 05/19] for testing @rogowski 's awesome work --- lib/radisk2.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/radisk2.js b/lib/radisk2.js index 0858d376..87fc7be0 100644 --- a/lib/radisk2.js +++ b/lib/radisk2.js @@ -1,4 +1,5 @@ ;(function(){ + console.log("RADISK 2!!!!"); function Radisk(opt){ @@ -515,7 +516,7 @@ window.Radisk = Radisk; } else { var Gun = require('../gun'); - var Radix = require('./radix'); + var Radix = require('./radix2'); try{ module.exports = Radisk }catch(e){} } From 9fc0adbbe6987d9d17984a5d6f31cfd5d3c658bc Mon Sep 17 00:00:00 2001 From: Hadar Date: Thu, 5 Sep 2019 14:40:24 +0300 Subject: [PATCH 06/19] add: reflect change in sea.js --- sea.js | 2436 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 1535 insertions(+), 901 deletions(-) diff --git a/sea.js b/sea.js index e58474f3..91bbd8c3 100644 --- a/sea.js +++ b/sea.js @@ -1,647 +1,1007 @@ -;(function(){ - +(function() { /* UNBUILD */ var root; - if(typeof window !== "undefined"){ root = window } - if(typeof global !== "undefined"){ root = global } + if (typeof window !== "undefined") { + root = window; + } + if (typeof global !== "undefined") { + root = global; + } root = root || {}; - var console = root.console || {log: function(){}}; - function USE(arg, req){ - return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){ - arg(mod = {exports: {}}); - USE[R(path)] = mod.exports; - } - function R(p){ - return p.split('/').slice(-1).toString().replace('.js',''); + var console = root.console || { log: function() {} }; + function USE(arg, req) { + return req + ? require(arg) + : arg.slice + ? USE[R(arg)] + : function(mod, path) { + arg((mod = { exports: {} })); + USE[R(path)] = mod.exports; + }; + function R(p) { + return p + .split("/") + .slice(-1) + .toString() + .replace(".js", ""); } } - if(typeof module !== "undefined"){ var common = module } + if (typeof module !== "undefined") { + var common = module; + } /* UNBUILD */ - ;USE(function(module){ + USE(function(module) { // Security, Encryption, and Authorization: SEA.js // MANDATORY READING: https://gun.eco/explainers/data/security.html // IT IS IMPLEMENTED IN A POLYFILL/SHIM APPROACH. // THIS IS AN EARLY ALPHA! - if(typeof window !== "undefined"){ module.window = window } + if (typeof window !== "undefined") { + module.window = window; + } var tmp = module.window || module; var SEA = tmp.SEA || {}; - if(SEA.window = module.window){ SEA.window.SEA = SEA } + if ((SEA.window = module.window)) { + SEA.window.SEA = SEA; + } - try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){} - module.exports = SEA; - })(USE, './root'); - - ;USE(function(module){ - var SEA = USE('./root'); - try{ if(SEA.window){ - if(location.protocol.indexOf('s') < 0 - && location.host.indexOf('localhost') < 0 - && location.protocol.indexOf('file:') < 0){ - location.protocol = 'https:'; // WebCrypto does NOT work without HTTPS! + try { + if (typeof common !== "undefined") { + common.exports = SEA; } - } }catch(e){} - })(USE, './https'); + } catch (e) {} + module.exports = SEA; + })(USE, "./root"); - ;USE(function(module){ + USE(function(module) { + var SEA = USE("./root"); + try { + if (SEA.window) { + if ( + location.protocol.indexOf("s") < 0 && + location.host.indexOf("localhost") < 0 && + location.protocol.indexOf("file:") < 0 + ) { + location.protocol = "https:"; // WebCrypto does NOT work without HTTPS! + } + } + } catch (e) {} + })(USE, "./https"); + + USE(function(module) { // This is Array extended to have .toString(['utf8'|'hex'|'base64']) function SeaArray() {} - Object.assign(SeaArray, { from: Array.from }) - SeaArray.prototype = Object.create(Array.prototype) - SeaArray.prototype.toString = function(enc, start, end) { enc = enc || 'utf8'; start = start || 0; - const length = this.length - if (enc === 'hex') { - const buf = new Uint8Array(this) - return [ ...Array(((end && (end + 1)) || length) - start).keys()] - .map((i) => buf[ i + start ].toString(16).padStart(2, '0')).join('') + Object.assign(SeaArray, { from: Array.from }); + SeaArray.prototype = Object.create(Array.prototype); + SeaArray.prototype.toString = function(enc, start, end) { + enc = enc || "utf8"; + start = start || 0; + const length = this.length; + if (enc === "hex") { + const buf = new Uint8Array(this); + return [...Array(((end && end + 1) || length) - start).keys()] + .map(i => buf[i + start].toString(16).padStart(2, "0")) + .join(""); } - if (enc === 'utf8') { - return Array.from( - { length: (end || length) - start }, - (_, i) => String.fromCharCode(this[ i + start]) - ).join('') + if (enc === "utf8") { + return Array.from({ length: (end || length) - start }, (_, i) => + String.fromCharCode(this[i + start]) + ).join(""); } - if (enc === 'base64') { - return btoa(this) + if (enc === "base64") { + return btoa(this); } - } + }; module.exports = SeaArray; - })(USE, './array'); + })(USE, "./array"); - ;USE(function(module){ + USE(function(module) { // This is Buffer implementation used in SEA. Functionality is mostly // compatible with NodeJS 'safe-buffer' and is used for encoding conversions // between binary and 'hex' | 'utf8' | 'base64' // See documentation and validation for safe implementation in: // https://github.com/feross/safe-buffer#update - var SeaArray = USE('./array'); + var SeaArray = USE("./array"); function SafeBuffer(...props) { - console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()') - return SafeBuffer.from(...props) + console.warn( + "new SafeBuffer() is depreciated, please use SafeBuffer.from()" + ); + return SafeBuffer.from(...props); } - SafeBuffer.prototype = Object.create(Array.prototype) + SafeBuffer.prototype = Object.create(Array.prototype); Object.assign(SafeBuffer, { // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' from() { if (!Object.keys(arguments).length) { - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + throw new TypeError( + "First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object." + ); } - const input = arguments[0] - let buf - if (typeof input === 'string') { - const enc = arguments[1] || 'utf8' - if (enc === 'hex') { - const bytes = input.match(/([\da-fA-F]{2})/g) - .map((byte) => parseInt(byte, 16)) + const input = arguments[0]; + let buf; + if (typeof input === "string") { + const enc = arguments[1] || "utf8"; + if (enc === "hex") { + const bytes = input + .match(/([\da-fA-F]{2})/g) + .map(byte => parseInt(byte, 16)); if (!bytes || !bytes.length) { - throw new TypeError('Invalid first argument for type \'hex\'.') + throw new TypeError("Invalid first argument for type 'hex'."); } - buf = SeaArray.from(bytes) - } else if (enc === 'utf8') { - const length = input.length - const words = new Uint16Array(length) - Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i)) - buf = SeaArray.from(words) - } else if (enc === 'base64') { - const dec = atob(input) - const length = dec.length - const bytes = new Uint8Array(length) - Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i)) - buf = SeaArray.from(bytes) - } else if (enc === 'binary') { - buf = SeaArray.from(input) + buf = SeaArray.from(bytes); + } else if (enc === "utf8") { + const length = input.length; + const words = new Uint16Array(length); + Array.from( + { length: length }, + (_, i) => (words[i] = input.charCodeAt(i)) + ); + buf = SeaArray.from(words); + } else if (enc === "base64") { + const dec = atob(input); + const length = dec.length; + const bytes = new Uint8Array(length); + Array.from( + { length: length }, + (_, i) => (bytes[i] = dec.charCodeAt(i)) + ); + buf = SeaArray.from(bytes); + } else if (enc === "binary") { + buf = SeaArray.from(input); } else { - console.info('SafeBuffer.from unknown encoding: '+enc) + console.info("SafeBuffer.from unknown encoding: " + enc); } - return buf + return buf; } - const byteLength = input.byteLength // what is going on here? FOR MARTTI - const length = input.byteLength ? input.byteLength : input.length + const byteLength = input.byteLength; // what is going on here? FOR MARTTI + const length = input.byteLength ? input.byteLength : input.length; if (length) { - let buf + let buf; if (input instanceof ArrayBuffer) { - buf = new Uint8Array(input) + buf = new Uint8Array(input); } - return SeaArray.from(buf || input) + return SeaArray.from(buf || input); } }, // This is 'safe-buffer.alloc' sans encoding support - alloc(length, fill = 0 /*, enc*/ ) { - return SeaArray.from(new Uint8Array(Array.from({ length: length }, () => fill))) + alloc(length, fill = 0 /*, enc*/) { + return SeaArray.from( + new Uint8Array(Array.from({ length: length }, () => fill)) + ); }, // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! allocUnsafe(length) { - return SeaArray.from(new Uint8Array(Array.from({ length : length }))) + return SeaArray.from(new Uint8Array(Array.from({ length: length }))); }, // This puts together array of array like members - concat(arr) { // octet array + concat(arr) { + // octet array if (!Array.isArray(arr)) { - throw new TypeError('First argument must be Array containing ArrayBuffer or Uint8Array instances.') + throw new TypeError( + "First argument must be Array containing ArrayBuffer or Uint8Array instances." + ); } - return SeaArray.from(arr.reduce((ret, item) => ret.concat(Array.from(item)), [])) + return SeaArray.from( + arr.reduce((ret, item) => ret.concat(Array.from(item)), []) + ); } - }) - SafeBuffer.prototype.from = SafeBuffer.from - SafeBuffer.prototype.toString = SeaArray.prototype.toString + }); + SafeBuffer.prototype.from = SafeBuffer.from; + SafeBuffer.prototype.toString = SeaArray.prototype.toString; module.exports = SafeBuffer; - })(USE, './buffer'); + })(USE, "./buffer"); - ;USE(function(module){ - const SEA = USE('./root') - const Buffer = USE('./buffer') - const api = {Buffer: Buffer} + USE(function(module) { + const SEA = USE("./root"); + const Buffer = USE("./buffer"); + const api = { Buffer: Buffer }; var o = {}; - if(SEA.window){ + if (SEA.window) { api.crypto = window.crypto || window.msCrypto; - api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle; + api.subtle = (api.crypto || o).subtle || (api.crypto || o).webkitSubtle; api.TextEncoder = window.TextEncoder; api.TextDecoder = window.TextDecoder; - api.random = (len) => Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) + api.random = len => + Buffer.from( + api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len))) + ); } - if(!api.crypto){try{ - var crypto = USE('crypto', 1); - const { TextEncoder, TextDecoder } = USE('text-encoding', 1) - Object.assign(api, { - crypto, - //subtle, - TextEncoder, - TextDecoder, - random: (len) => Buffer.from(crypto.randomBytes(len)) - }); - //try{ - const WebCrypto = USE('node-webcrypto-ossl', 1); - api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH - //}catch(e){ + if (!api.crypto) { + try { + var crypto = USE("crypto", 1); + const { TextEncoder, TextDecoder } = USE("text-encoding", 1); + Object.assign(api, { + crypto, + //subtle, + TextEncoder, + TextDecoder, + random: len => Buffer.from(crypto.randomBytes(len)) + }); + //try{ + const WebCrypto = USE("node-webcrypto-ossl", 1); + api.ossl = api.subtle = new WebCrypto({ directory: "ossl" }).subtle; // ECDH + //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); - //} - }catch(e){ - console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!"); - OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; - }} + //} + } catch (e) { + console.log( + "node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!" + ); + OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; + } + } - module.exports = api - })(USE, './shim'); + module.exports = api; + })(USE, "./shim"); - ;USE(function(module){ - var SEA = USE('./root'); - var Buffer = USE('./buffer'); + USE(function(module) { + var SEA = USE("./root"); + var Buffer = USE("./buffer"); var s = {}; - s.pbkdf2 = {hash: 'SHA-256', iter: 100000, ks: 64}; + s.pbkdf2 = { hash: "SHA-256", iter: 100000, ks: 64 }; s.ecdsa = { - pair: {name: 'ECDSA', namedCurve: 'P-256'}, - sign: {name: 'ECDSA', hash: {name: 'SHA-256'}} + pair: { name: "ECDSA", namedCurve: "P-256" }, + sign: { name: "ECDSA", hash: { name: "SHA-256" } } }; - s.ecdh = {name: 'ECDH', namedCurve: 'P-256'}; + s.ecdh = { name: "ECDH", namedCurve: "P-256" }; // This creates Web Cryptography API compliant JWK for sign/verify purposes - s.jwk = function(pub, d){ // d === priv - pub = pub.split('.'); - var x = pub[0], y = pub[1]; - var jwk = {kty: "EC", crv: "P-256", x: x, y: y, ext: true}; - jwk.key_ops = d ? ['sign'] : ['verify']; - if(d){ jwk.d = d } + s.jwk = function(pub, d) { + // d === priv + pub = pub.split("."); + var x = pub[0], + y = pub[1]; + var jwk = { kty: "EC", crv: "P-256", x: x, y: y, ext: true }; + jwk.key_ops = d ? ["sign"] : ["verify"]; + if (d) { + jwk.d = d; + } return jwk; }; s.recall = { validity: 12 * 60 * 60, // internally in seconds : 12 hours - hook: function(props){ return props } // { iat, exp, alias, remember } // or return new Promise((resolve, reject) => resolve(props) + hook: function(props) { + return props; + } // { iat, exp, alias, remember } // or return new Promise((resolve, reject) => resolve(props) }; - s.check = function(t){ return (typeof t == 'string') && ('SEA{' === t.slice(0,4)) } - s.parse = function p(t){ try { - var yes = (typeof t == 'string'); - if(yes && 'SEA{' === t.slice(0,4)){ t = t.slice(3) } - return yes ? JSON.parse(t) : t; + s.check = function(t) { + return typeof t == "string" && "SEA{" === t.slice(0, 4); + }; + s.parse = function p(t) { + try { + var yes = typeof t == "string"; + if (yes && "SEA{" === t.slice(0, 4)) { + t = t.slice(3); + } + return yes ? JSON.parse(t) : t; } catch (e) {} return t; - } + }; SEA.opt = s; - module.exports = s - })(USE, './settings'); + module.exports = s; + })(USE, "./settings"); - ;USE(function(module){ - var shim = USE('./shim'); - module.exports = async function(d, o){ - var t = (typeof d == 'string')? d : JSON.stringify(d); - var hash = await shim.subtle.digest({name: o||'SHA-256'}, new shim.TextEncoder().encode(t)); + USE(function(module) { + var shim = USE("./shim"); + module.exports = async function(d, o) { + var t = typeof d == "string" ? d : JSON.stringify(d); + var hash = await shim.subtle.digest( + { name: o || "SHA-256" }, + new shim.TextEncoder().encode(t) + ); return shim.Buffer.from(hash); - } - })(USE, './sha256'); + }; + })(USE, "./sha256"); - ;USE(function(module){ + USE(function(module) { // This internal func returns SHA-1 hashed data for KeyID generation - const __shim = USE('./shim') - const subtle = __shim.subtle - const ossl = __shim.ossl ? __shim.ossl : subtle - const sha1hash = (b) => ossl.digest({name: 'SHA-1'}, new ArrayBuffer(b)) - module.exports = sha1hash - })(USE, './sha1'); + const __shim = USE("./shim"); + const subtle = __shim.subtle; + const ossl = __shim.ossl ? __shim.ossl : subtle; + const sha1hash = b => ossl.digest({ name: "SHA-1" }, new ArrayBuffer(b)); + module.exports = sha1hash; + })(USE, "./sha1"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - var sha = USE('./sha256'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + var sha = USE("./sha256"); var u; - SEA.work = SEA.work || (async (data, pair, cb, opt) => { try { // used to be named `proof` - var salt = (pair||{}).epub || pair; // epub not recommended, salt should be random! - var opt = opt || {}; - if(salt instanceof Function){ - cb = salt; - salt = u; - } - salt = salt || shim.random(9); - data = (typeof data == 'string')? data : JSON.stringify(data); - if('sha' === (opt.name||'').toLowerCase().slice(0,3)){ - var rsha = shim.Buffer.from(await sha(data, opt.name), 'binary').toString(opt.encode || 'base64') - if(cb){ try{ cb(rsha) }catch(e){console.log(e)} } - return rsha; - } - var key = await (shim.ossl || shim.subtle).importKey('raw', new shim.TextEncoder().encode(data), {name: opt.name || 'PBKDF2'}, false, ['deriveBits']); - var work = await (shim.ossl || shim.subtle).deriveBits({ - name: opt.name || 'PBKDF2', - iterations: opt.iterations || S.pbkdf2.iter, - salt: new shim.TextEncoder().encode(opt.salt || salt), - hash: opt.hash || S.pbkdf2.hash, - }, key, opt.length || (S.pbkdf2.ks * 8)) - data = shim.random(data.length) // Erase data in case of passphrase - var r = shim.Buffer.from(work, 'binary').toString(opt.encode || 'base64') - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + SEA.work = + SEA.work || + (async (data, pair, cb, opt) => { + try { + // used to be named `proof` + var salt = (pair || {}).epub || pair; // epub not recommended, salt should be random! + var opt = opt || {}; + if (salt instanceof Function) { + cb = salt; + salt = u; + } + salt = salt || shim.random(9); + data = typeof data == "string" ? data : JSON.stringify(data); + if ("sha" === (opt.name || "").toLowerCase().slice(0, 3)) { + var rsha = shim.Buffer.from( + await sha(data, opt.name), + "binary" + ).toString(opt.encode || "base64"); + if (cb) { + try { + cb(rsha); + } catch (e) { + console.log(e); + } + } + return rsha; + } + var key = await (shim.ossl || shim.subtle).importKey( + "raw", + new shim.TextEncoder().encode(data), + { name: opt.name || "PBKDF2" }, + false, + ["deriveBits"] + ); + var work = await (shim.ossl || shim.subtle).deriveBits( + { + name: opt.name || "PBKDF2", + iterations: opt.iterations || S.pbkdf2.iter, + salt: new shim.TextEncoder().encode(opt.salt || salt), + hash: opt.hash || S.pbkdf2.hash + }, + key, + opt.length || S.pbkdf2.ks * 8 + ); + data = shim.random(data.length); // Erase data in case of passphrase + var r = shim.Buffer.from(work, "binary").toString( + opt.encode || "base64" + ); + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); module.exports = SEA.work; - })(USE, './work'); + })(USE, "./work"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); - SEA.name = SEA.name || (async (cb, opt) => { try { - if(cb){ try{ cb() }catch(e){console.log(e)} } - return; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + SEA.name = + SEA.name || + (async (cb, opt) => { + try { + if (cb) { + try { + cb(); + } catch (e) { + console.log(e); + } + } + return; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); //SEA.pair = async (data, proof, cb) => { try { - SEA.pair = SEA.pair || (async (cb, opt) => { try { + SEA.pair = + SEA.pair || + (async (cb, opt) => { + try { + var ecdhSubtle = shim.ossl || shim.subtle; + // First: ECDSA keys for signing/verifying... + var sa = await shim.subtle + .generateKey(S.ecdsa.pair, true, ["sign", "verify"]) + .then(async keys => { + // privateKey scope doesn't leak out from here! + //const { d: priv } = await shim.subtle.exportKey('jwk', keys.privateKey) + var key = {}; + key.priv = (await shim.subtle.exportKey( + "jwk", + keys.privateKey + )).d; + var pub = await shim.subtle.exportKey("jwk", keys.publicKey); + //const pub = Buff.from([ x, y ].join(':')).toString('base64') // old + key.pub = pub.x + "." + pub.y; // new + // x and y are already base64 + // pub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) + // but split on a non-base64 letter. + return key; + }); - var ecdhSubtle = shim.ossl || shim.subtle; - // First: ECDSA keys for signing/verifying... - var sa = await shim.subtle.generateKey(S.ecdsa.pair, true, [ 'sign', 'verify' ]) - .then(async (keys) => { - // privateKey scope doesn't leak out from here! - //const { d: priv } = await shim.subtle.exportKey('jwk', keys.privateKey) - var key = {}; - key.priv = (await shim.subtle.exportKey('jwk', keys.privateKey)).d; - var pub = await shim.subtle.exportKey('jwk', keys.publicKey); - //const pub = Buff.from([ x, y ].join(':')).toString('base64') // old - key.pub = pub.x+'.'+pub.y; // new - // x and y are already base64 - // pub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) - // but split on a non-base64 letter. - return key; - }) - - // To include PGPv4 kind of keyId: - // const pubId = await SEA.keyid(keys.pub) - // Next: ECDH keys for encryption/decryption... + // To include PGPv4 kind of keyId: + // const pubId = await SEA.keyid(keys.pub) + // Next: ECDH keys for encryption/decryption... - try{ - var dh = await ecdhSubtle.generateKey(S.ecdh, true, ['deriveKey']) - .then(async (keys) => { - // privateKey scope doesn't leak out from here! - var key = {}; - key.epriv = (await ecdhSubtle.exportKey('jwk', keys.privateKey)).d; - var pub = await ecdhSubtle.exportKey('jwk', keys.publicKey); - //const epub = Buff.from([ ex, ey ].join(':')).toString('base64') // old - key.epub = pub.x+'.'+pub.y; // new - // ex and ey are already base64 - // epub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) - // but split on a non-base64 letter. - return key; - }) - }catch(e){ - if(SEA.window){ throw e } - if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') } - else { throw e } - } dh = dh || {}; + try { + var dh = await ecdhSubtle + .generateKey(S.ecdh, true, ["deriveKey"]) + .then(async keys => { + // privateKey scope doesn't leak out from here! + var key = {}; + key.epriv = (await ecdhSubtle.exportKey( + "jwk", + keys.privateKey + )).d; + var pub = await ecdhSubtle.exportKey("jwk", keys.publicKey); + //const epub = Buff.from([ ex, ey ].join(':')).toString('base64') // old + key.epub = pub.x + "." + pub.y; // new + // ex and ey are already base64 + // epub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) + // but split on a non-base64 letter. + return key; + }); + } catch (e) { + if (SEA.window) { + throw e; + } + if (e == "Error: ECDH is not a supported algorithm") { + console.log("Ignoring ECDH..."); + } else { + throw e; + } + } + dh = dh || {}; - var r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv } - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + var r = { + pub: sa.pub, + priv: sa.priv, + /* pubId, */ epub: dh.epub, + epriv: dh.epriv + }; + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); module.exports = SEA.pair; - })(USE, './pair'); + })(USE, "./pair"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - var sha = USE('./sha256'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + var sha = USE("./sha256"); var u; - SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try { - opt = opt || {}; - if(!(pair||opt).priv){ - pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why}); - } - if(u === data){ throw '`undefined` not allowed.' } - var json = S.parse(data); - var check = opt.check = opt.check || json; - if(SEA.verify && (SEA.opt.check(check) || (check && check.s && check.m)) - && u !== await SEA.verify(check, pair)){ // don't sign if we already signed it. - var r = S.parse(check); - if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } - var pub = pair.pub; - var priv = pair.priv; - var jwk = S.jwk(pub, priv); - var hash = await sha(json); - var sig = await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['sign']) - .then((key) => (shim.ossl || shim.subtle).sign(S.ecdsa.sign, key, new Uint8Array(hash))) // privateKey scope doesn't leak out from here! - var r = {m: json, s: shim.Buffer.from(sig, 'binary').toString(opt.encode || 'base64')} - if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } + SEA.sign = + SEA.sign || + (async (data, pair, cb, opt) => { + try { + opt = opt || {}; + if (!(pair || opt).priv) { + pair = await SEA.I(null, { what: data, how: "sign", why: opt.why }); + } + if (u === data) { + throw "`undefined` not allowed."; + } + var json = S.parse(data); + var check = (opt.check = opt.check || json); + if ( + SEA.verify && + (SEA.opt.check(check) || (check && check.s && check.m)) && + u !== (await SEA.verify(check, pair)) + ) { + // don't sign if we already signed it. + var r = S.parse(check); + if (!opt.raw) { + r = "SEA" + JSON.stringify(r); + } + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } + var pub = pair.pub; + var priv = pair.priv; + var jwk = S.jwk(pub, priv); + var hash = await sha(json); + var sig = await (shim.ossl || shim.subtle) + .importKey("jwk", jwk, S.ecdsa.pair, false, ["sign"]) + .then(key => + (shim.ossl || shim.subtle).sign( + S.ecdsa.sign, + key, + new Uint8Array(hash) + ) + ); // privateKey scope doesn't leak out from here! + var r = { + m: json, + s: shim.Buffer.from(sig, "binary").toString(opt.encode || "base64") + }; + if (!opt.raw) { + r = "SEA" + JSON.stringify(r); + } - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); module.exports = SEA.sign; - })(USE, './sign'); + })(USE, "./sign"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - var sha = USE('./sha256'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + var sha = USE("./sha256"); var u; - SEA.verify = SEA.verify || (async (data, pair, cb, opt) => { try { - var json = S.parse(data); - if(false === pair){ // don't verify! - var raw = S.parse(json.m); - if(cb){ try{ cb(raw) }catch(e){console.log(e)} } - return raw; - } - opt = opt || {}; - // SEA.I // verify is free! Requires no user permission. - var pub = pair.pub || pair; - var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['verify']); - var hash = await sha(json.m); - var buf, sig, check, tmp; try{ - buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT! - sig = new Uint8Array(buf); - check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)); - if(!check){ throw "Signature did not match." } - }catch(e){ - if(SEA.opt.fallback){ - return await SEA.opt.fall_verify(data, pair, cb, opt); - } - } - var r = check? S.parse(json.m) : u; + SEA.verify = + SEA.verify || + (async (data, pair, cb, opt) => { + try { + var json = S.parse(data); + if (false === pair) { + // don't verify! + var raw = S.parse(json.m); + if (cb) { + try { + cb(raw); + } catch (e) { + console.log(e); + } + } + return raw; + } + opt = opt || {}; + // SEA.I // verify is free! Requires no user permission. + var pub = pair.pub || pair; + var key = SEA.opt.slow_leak + ? await SEA.opt.slow_leak(pub) + : await (shim.ossl || shim.subtle).importKey( + "jwk", + jwk, + S.ecdsa.pair, + false, + ["verify"] + ); + var hash = await sha(json.m); + var buf, sig, check, tmp; + try { + buf = shim.Buffer.from(json.s, opt.encode || "base64"); // NEW DEFAULT! + sig = new Uint8Array(buf); + check = await (shim.ossl || shim.subtle).verify( + S.ecdsa.sign, + key, + sig, + new Uint8Array(hash) + ); + if (!check) { + throw "Signature did not match."; + } + } catch (e) { + if (SEA.opt.fallback) { + return await SEA.opt.fall_verify(data, pair, cb, opt); + } + } + var r = check ? S.parse(json.m) : u; - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); // mismatched owner FOR MARTTI - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); // mismatched owner FOR MARTTI + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); module.exports = SEA.verify; // legacy & ossl leak mitigation: var knownKeys = {}; - var keyForPair = SEA.opt.slow_leak = pair => { + var keyForPair = (SEA.opt.slow_leak = pair => { if (knownKeys[pair]) return knownKeys[pair]; var jwk = S.jwk(pair); - knownKeys[pair] = (shim.ossl || shim.subtle).importKey("jwk", jwk, S.ecdsa.pair, false, ["verify"]); + knownKeys[pair] = (shim.ossl || shim.subtle).importKey( + "jwk", + jwk, + S.ecdsa.pair, + false, + ["verify"] + ); return knownKeys[pair]; - }; + }); - - SEA.opt.fall_verify = async function(data, pair, cb, opt, f){ - if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1; - var json = S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub); - var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. - var buf; var sig; var check; try{ - buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT! - sig = new Uint8Array(buf) - check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)) - if(!check){ throw "Signature did not match." } - }catch(e){ - buf = shim.Buffer.from(json.s, 'utf8') // AUTO BACKWARD OLD UTF8 DATA! - sig = new Uint8Array(buf) - check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)) - if(!check){ throw "Signature did not match." } + SEA.opt.fall_verify = async function(data, pair, cb, opt, f) { + if (f === SEA.opt.fallback) { + throw "Signature did not match"; + } + f = f || 1; + var json = S.parse(data), + pub = pair.pub || pair, + key = await SEA.opt.slow_leak(pub); + var hash = + f <= SEA.opt.fallback + ? shim.Buffer.from( + await shim.subtle.digest( + { name: "SHA-256" }, + new shim.TextEncoder().encode(S.parse(json.m)) + ) + ) + : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. + var buf; + var sig; + var check; + try { + buf = shim.Buffer.from(json.s, opt.encode || "base64"); // NEW DEFAULT! + sig = new Uint8Array(buf); + check = await (shim.ossl || shim.subtle).verify( + S.ecdsa.sign, + key, + sig, + new Uint8Array(hash) + ); + if (!check) { + throw "Signature did not match."; + } + } catch (e) { + buf = shim.Buffer.from(json.s, "utf8"); // AUTO BACKWARD OLD UTF8 DATA! + sig = new Uint8Array(buf); + check = await (shim.ossl || shim.subtle).verify( + S.ecdsa.sign, + key, + sig, + new Uint8Array(hash) + ); + if (!check) { + throw "Signature did not match."; + } + } + var r = check ? S.parse(json.m) : u; + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } } - var r = check? S.parse(json.m) : u; - if(cb){ try{ cb(r) }catch(e){console.log(e)} } return r; - } + }; SEA.opt.fallback = 2; + })(USE, "./verify"); - })(USE, './verify'); - - ;USE(function(module){ - var shim = USE('./shim'); - var sha256hash = USE('./sha256'); + USE(function(module) { + var shim = USE("./shim"); + var sha256hash = USE("./sha256"); const importGen = async (key, salt, opt) => { //const combo = shim.Buffer.concat([shim.Buffer.from(key, 'utf8'), salt || shim.random(8)]).toString('utf8') // old var opt = opt || {}; - const combo = key + (salt || shim.random(8)).toString('utf8'); // new - const hash = shim.Buffer.from(await sha256hash(combo), 'binary') - return await shim.subtle.importKey('raw', new Uint8Array(hash), opt.name || 'AES-GCM', false, ['encrypt', 'decrypt']) - } + const combo = key + (salt || shim.random(8)).toString("utf8"); // new + const hash = shim.Buffer.from(await sha256hash(combo), "binary"); + return await shim.subtle.importKey( + "raw", + new Uint8Array(hash), + opt.name || "AES-GCM", + false, + ["encrypt", "decrypt"] + ); + }; module.exports = importGen; - })(USE, './aeskey'); + })(USE, "./aeskey"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - var aeskey = USE('./aeskey'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + var aeskey = USE("./aeskey"); var u; - SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try { - opt = opt || {}; - var key = (pair||opt).epriv || pair; - if(u === data){ throw '`undefined` not allowed.' } - if(!key){ - pair = await SEA.I(null, {what: data, how: 'encrypt', why: opt.why}); - key = pair.epriv || pair; - } - var msg = (typeof data == 'string')? data : JSON.stringify(data); - var rand = {s: shim.random(9), iv: shim.random(15)}; // consider making this 9 and 15 or 18 or 12 to reduce == padding. - var ct = await aeskey(key, rand.s, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).encrypt({ // Keeping the AES key scope as private as possible... - name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv) - }, aes, new shim.TextEncoder().encode(msg))); - var r = { - ct: shim.Buffer.from(ct, 'binary').toString(opt.encode || 'base64'), - iv: rand.iv.toString(opt.encode || 'base64'), - s: rand.s.toString(opt.encode || 'base64') - } - if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } + SEA.encrypt = + SEA.encrypt || + (async (data, pair, cb, opt) => { + try { + opt = opt || {}; + var key = (pair || opt).epriv || pair; + if (u === data) { + throw "`undefined` not allowed."; + } + if (!key) { + pair = await SEA.I(null, { + what: data, + how: "encrypt", + why: opt.why + }); + key = pair.epriv || pair; + } + var msg = typeof data == "string" ? data : JSON.stringify(data); + var rand = { s: shim.random(9), iv: shim.random(15) }; // consider making this 9 and 15 or 18 or 12 to reduce == padding. + var ct = await aeskey(key, rand.s, opt).then(aes => + shim /*shim.ossl ||*/.subtle + .encrypt( + { + // Keeping the AES key scope as private as possible... + name: opt.name || "AES-GCM", + iv: new Uint8Array(rand.iv) + }, + aes, + new shim.TextEncoder().encode(msg) + ) + ); + var r = { + ct: shim.Buffer.from(ct, "binary").toString(opt.encode || "base64"), + iv: rand.iv.toString(opt.encode || "base64"), + s: rand.s.toString(opt.encode || "base64") + }; + if (!opt.raw) { + r = "SEA" + JSON.stringify(r); + } - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); module.exports = SEA.encrypt; - })(USE, './encrypt'); + })(USE, "./encrypt"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - var aeskey = USE('./aeskey'); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + var aeskey = USE("./aeskey"); - SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try { - opt = opt || {}; - var key = (pair||opt).epriv || pair; - if(!key){ - pair = await SEA.I(null, {what: data, how: 'decrypt', why: opt.why}); - key = pair.epriv || pair; - } - var json = S.parse(data); - var buf, bufiv, bufct; try{ - buf = shim.Buffer.from(json.s, opt.encode || 'base64'); - bufiv = shim.Buffer.from(json.iv, opt.encode || 'base64'); - bufct = shim.Buffer.from(json.ct, opt.encode || 'base64'); - var ct = await aeskey(key, buf, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).decrypt({ // Keeping aesKey scope as private as possible... - name: opt.name || 'AES-GCM', iv: new Uint8Array(bufiv) - }, aes, new Uint8Array(bufct))); - }catch(e){ - if('utf8' === opt.encode){ throw "Could not decrypt" } - if(SEA.opt.fallback){ - opt.encode = 'utf8'; - return await SEA.decrypt(data, pair, cb, opt); + SEA.decrypt = + SEA.decrypt || + (async (data, pair, cb, opt) => { + try { + opt = opt || {}; + var key = (pair || opt).epriv || pair; + if (!key) { + pair = await SEA.I(null, { + what: data, + how: "decrypt", + why: opt.why + }); + key = pair.epriv || pair; + } + var json = S.parse(data); + var buf, bufiv, bufct; + try { + buf = shim.Buffer.from(json.s, opt.encode || "base64"); + bufiv = shim.Buffer.from(json.iv, opt.encode || "base64"); + bufct = shim.Buffer.from(json.ct, opt.encode || "base64"); + var ct = await aeskey(key, buf, opt).then(aes => + shim /*shim.ossl ||*/.subtle + .decrypt( + { + // Keeping aesKey scope as private as possible... + name: opt.name || "AES-GCM", + iv: new Uint8Array(bufiv) + }, + aes, + new Uint8Array(bufct) + ) + ); + } catch (e) { + if ("utf8" === opt.encode) { + throw "Could not decrypt"; + } + if (SEA.opt.fallback) { + opt.encode = "utf8"; + return await SEA.decrypt(data, pair, cb, opt); + } + } + var r = S.parse(new shim.TextDecoder("utf8").decode(ct)); + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; } - } - var r = S.parse(new shim.TextDecoder('utf8').decode(ct)); - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + }); module.exports = SEA.decrypt; - })(USE, './decrypt'); + })(USE, "./decrypt"); - ;USE(function(module){ - var SEA = USE('./root'); - var shim = USE('./shim'); - var S = USE('./settings'); - // Derive shared secret from other's pub and my epub/epriv - SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try { - opt = opt || {}; - if(!pair || !pair.epriv || !pair.epub){ - pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why}); - } - var pub = key.epub || key; - var epub = pair.epub; - var epriv = pair.epriv; - var ecdhSubtle = shim.ossl || shim.subtle; - var pubKeyData = keysToEcdhJwk(pub); - var props = Object.assign(S.ecdh, { public: await ecdhSubtle.importKey(...pubKeyData, true, []) }); - var privKeyData = keysToEcdhJwk(epub, epriv); - var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']).then(async (privKey) => { - // privateKey scope doesn't leak out from here! - var derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt' ]); - return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k); - }) - var r = derived; - if(cb){ try{ cb(r) }catch(e){console.log(e)} } - return r; - } catch(e) { - console.log(e); - SEA.err = e; - if(SEA.throw){ throw e } - if(cb){ cb() } - return; - }}); + USE(function(module) { + var SEA = USE("./root"); + var shim = USE("./shim"); + var S = USE("./settings"); + // Derive shared secret from other's pub and my epub/epriv + SEA.secret = + SEA.secret || + (async (key, pair, cb, opt) => { + try { + opt = opt || {}; + if (!pair || !pair.epriv || !pair.epub) { + pair = await SEA.I(null, { + what: key, + how: "secret", + why: opt.why + }); + } + var pub = key.epub || key; + var epub = pair.epub; + var epriv = pair.epriv; + var ecdhSubtle = shim.ossl || shim.subtle; + var pubKeyData = keysToEcdhJwk(pub); + var props = Object.assign( + { public: await ecdhSubtle.importKey(...pubKeyData, true, []) }, + S.ecdh + ); + var privKeyData = keysToEcdhJwk(epub, epriv); + var derived = await ecdhSubtle + .importKey(...privKeyData, false, ["deriveKey"]) + .then(async privKey => { + // privateKey scope doesn't leak out from here! + var derivedKey = await ecdhSubtle.deriveKey( + props, + privKey, + { name: "AES-GCM", length: 256 }, + true, + ["encrypt", "decrypt"] + ); + return ecdhSubtle.exportKey("jwk", derivedKey).then(({ k }) => k); + }); + var r = derived; + if (cb) { + try { + cb(r); + } catch (e) { + console.log(e); + } + } + return r; + } catch (e) { + console.log(e); + SEA.err = e; + if (SEA.throw) { + throw e; + } + if (cb) { + cb(); + } + return; + } + }); // can this be replaced with settings.jwk? - var keysToEcdhJwk = (pub, d) => { // d === priv + var keysToEcdhJwk = (pub, d) => { + // d === priv //var [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old - var [ x, y ] = pub.split('.') // new - var jwk = d ? { d: d } : {} - return [ // Use with spread returned value... - 'jwk', - Object.assign( - jwk, - { x: x, y: y, kty: 'EC', crv: 'P-256', ext: true } - ), // ??? refactor + var [x, y] = pub.split("."); // new + var jwk = d ? { d: d } : {}; + return [ + // Use with spread returned value... + "jwk", + Object.assign(jwk, { x: x, y: y, kty: "EC", crv: "P-256", ext: true }), // ??? refactor S.ecdh - ] - } + ]; + }; module.exports = SEA.secret; - })(USE, './secret'); + })(USE, "./secret"); - ;USE(function(module){ - var shim = USE('./shim'); + USE(function(module) { + var shim = USE("./shim"); // Practical examples about usage found from ./test/common.js - var SEA = USE('./root'); - SEA.work = USE('./work'); - SEA.sign = USE('./sign'); - SEA.verify = USE('./verify'); - SEA.encrypt = USE('./encrypt'); - SEA.decrypt = USE('./decrypt'); + var SEA = USE("./root"); + SEA.work = USE("./work"); + SEA.sign = USE("./sign"); + SEA.verify = USE("./verify"); + SEA.encrypt = USE("./encrypt"); + SEA.decrypt = USE("./decrypt"); SEA.random = SEA.random || shim.random; // This is Buffer used in SEA and usable from Gun/SEA application also. // For documentation see https://nodejs.org/api/buffer.html - SEA.Buffer = SEA.Buffer || USE('./buffer'); + SEA.Buffer = SEA.Buffer || USE("./buffer"); // These SEA functions support now ony Promises or // async/await (compatible) code, use those like Promises. @@ -649,25 +1009,31 @@ // Creates a wrapper library around Web Crypto API // for various AES, ECDSA, PBKDF2 functions we called above. // Calculate public key KeyID aka PGPv4 (result: 8 bytes as hex string) - SEA.keyid = SEA.keyid || (async (pub) => { - try { - // base64('base64(x):base64(y)') => Buffer(xy) - const pb = Buffer.concat( - pub.replace(/-/g, '+').replace(/_/g, '/').split('.') - .map((t) => Buffer.from(t, 'base64')) - ) - // id is PGPv4 compliant raw key - const id = Buffer.concat([ - Buffer.from([0x99, pb.length / 0x100, pb.length % 0x100]), pb - ]) - const sha1 = await sha1hash(id) - const hash = Buffer.from(sha1, 'binary') - return hash.toString('hex', hash.length - 8) // 16-bit ID as hex - } catch (e) { - console.log(e) - throw e - } - }); + SEA.keyid = + SEA.keyid || + (async pub => { + try { + // base64('base64(x):base64(y)') => Buffer(xy) + const pb = Buffer.concat( + pub + .replace(/-/g, "+") + .replace(/_/g, "/") + .split(".") + .map(t => Buffer.from(t, "base64")) + ); + // id is PGPv4 compliant raw key + const id = Buffer.concat([ + Buffer.from([0x99, pb.length / 0x100, pb.length % 0x100]), + pb + ]); + const sha1 = await sha1hash(id); + const hash = Buffer.from(sha1, "binary"); + return hash.toString("hex", hash.length - 8); // 16-bit ID as hex + } catch (e) { + console.log(e); + throw e; + } + }); // all done! // Obviously it is missing MANY necessary features. This is only an alpha release. // Please experiment with it, audit what I've done so far, and complain about what needs to be added. @@ -677,82 +1043,108 @@ // But all other behavior needs to be equally easy, like opinionated ways of // Adding friends (trusted public keys), sending private messages, etc. // Cheers! Tell me what you think. - var Gun = (SEA.window||{}).Gun || USE((typeof common == "undefined"?'.':'')+'./gun', 1); + var Gun = + (SEA.window || {}).Gun || + USE((typeof common == "undefined" ? "." : "") + "./gun", 1); Gun.SEA = SEA; SEA.GUN = SEA.Gun = Gun; - module.exports = SEA - })(USE, './sea'); + module.exports = SEA; + })(USE, "./sea"); - ;USE(function(module){ - var Gun = USE('./sea').Gun; - Gun.chain.then = function(cb){ - var gun = this, p = (new Promise(function(res, rej){ - gun.once(res); - })); - return cb? p.then(cb) : p; - } - })(USE, './then'); + USE(function(module) { + var Gun = USE("./sea").Gun; + Gun.chain.then = function(cb) { + var gun = this, + p = new Promise(function(res, rej) { + gun.once(res); + }); + return cb ? p.then(cb) : p; + }; + })(USE, "./then"); - ;USE(function(module){ - var SEA = USE('./sea'); + USE(function(module) { + var SEA = USE("./sea"); var Gun = SEA.Gun; - var then = USE('./then'); + var then = USE("./then"); - function User(root){ - this._ = {$: this}; + function User(root) { + this._ = { $: this }; } - User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill + User.prototype = (function() { + function F() {} + F.prototype = Gun.chain; + return new F(); + })(); // Object.create polyfill User.prototype.constructor = User; // let's extend the gun chain with a `user` function. // only one user can be logged in at a time, per gun instance. - Gun.chain.user = function(pub){ - var gun = this, root = gun.back(-1), user; - if(pub){ return root.get('~'+pub) } - if(user = root.back('user')){ return user } - var root = (root._), at = root, uuid = at.opt.uuid || Gun.state.lex; - (at = (user = at.user = gun.chain(new User))._).opt = {}; - at.opt.uuid = function(cb){ - var id = uuid(), pub = root.user; - if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id } - id = id + '~' + pub + '.'; - if(cb && cb.call){ cb(null, id) } - return id; + Gun.chain.user = function(pub) { + var gun = this, + root = gun.back(-1), + user; + if (pub) { + return root.get("~" + pub); } + if ((user = root.back("user"))) { + return user; + } + var root = root._, + at = root, + uuid = at.opt.uuid || Gun.state.lex; + (at = (user = at.user = gun.chain(new User()))._).opt = {}; + at.opt.uuid = function(cb) { + var id = uuid(), + pub = root.user; + if (!pub || !(pub = pub.is) || !(pub = pub.pub)) { + return id; + } + id = id + "~" + pub + "."; + if (cb && cb.call) { + cb(null, id); + } + return id; + }; return user; - } + }; Gun.User = User; module.exports = User; - })(USE, './user'); + })(USE, "./user"); - ;USE(function(module){ + USE(function(module) { // TODO: This needs to be split into all separate functions. // Not just everything thrown into 'create'. - var SEA = USE('./sea'); - var User = USE('./user'); - var authsettings = USE('./settings'); + var SEA = USE("./sea"); + var User = USE("./user"); + var authsettings = USE("./settings"); var Gun = SEA.Gun; - var noop = function(){}; + var noop = function() {}; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(alias, pass, cb, opt){ - var gun = this, cat = (gun._), root = gun.back(-1); + User.prototype.create = function(alias, pass, cb, opt) { + var gun = this, + cat = gun._, + root = gun.back(-1); cb = cb || noop; - if(cat.ing){ - cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); + if (cat.ing) { + cb({ + err: Gun.log("User is already being created or authenticated!"), + wait: true + }); return gun; } cat.ing = true; opt = opt || {}; - var act = {}, u; - act.a = function(pubs){ + var act = {}, + u; + act.a = function(pubs) { act.pubs = pubs; - if(pubs && !opt.already){ + if (pubs && !opt.already) { // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. - var ack = {err: Gun.log('User already created!')}; + var ack = { err: Gun.log("User already created!") }; cat.ing = false; cb(ack); gun.leave(); @@ -760,230 +1152,303 @@ } act.salt = Gun.text.random(64); // pseudo-randomly create a salt, then use PBKDF2 function to extend the password with it. SEA.work(pass, act.salt, act.b); // this will take some short amount of time to produce a proof, which slows brute force attacks. - } - act.b = function(proof){ + }; + act.b = function(proof) { act.proof = proof; SEA.pair(act.c); // now we have generated a brand new ECDSA key pair for the user account. - } - act.c = function(pair){ var tmp; + }; + act.c = function(pair) { + var tmp; act.pair = pair || {}; - if(tmp = cat.root.user){ + if ((tmp = cat.root.user)) { tmp._.sea = pair; - tmp.is = {pub: pair.pub, epub: pair.epub, alias: alias}; + tmp.is = { pub: pair.pub, epub: pair.epub, alias: alias }; } // the user's public key doesn't need to be signed. But everything else needs to be signed with it! // we have now automated it! clean up these extra steps now! - act.data = {pub: pair.pub}; + act.data = { pub: pair.pub }; act.d(); - } - act.d = function(){ + }; + act.d = function() { act.data.alias = alias; act.e(); - } - act.e = function(){ - act.data.epub = act.pair.epub; - SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f, {raw:1}); // to keep the private key safe, we AES encrypt it with the proof of work! - } - act.f = function(auth){ - act.data.auth = JSON.stringify({ek: auth, s: act.salt}); + }; + act.e = function() { + act.data.epub = act.pair.epub; + SEA.encrypt( + { priv: act.pair.priv, epriv: act.pair.epriv }, + act.proof, + act.f, + { raw: 1 } + ); // to keep the private key safe, we AES encrypt it with the proof of work! + }; + act.f = function(auth) { + act.data.auth = JSON.stringify({ ek: auth, s: act.salt }); act.g(act.data.auth); - } - act.g = function(auth){ var tmp; + }; + act.g = function(auth) { + var tmp; act.data.auth = act.data.auth || auth; - root.get(tmp = '~'+act.pair.pub).put(act.data); // awesome, now we can actually save the user with their public key as their ID. - root.get('~@'+alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. - setTimeout(function(){ // we should be able to delete this now, right? - cat.ing = false; - cb({ok: 0, pub: act.pair.pub}); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) - if(noop === cb){ gun.auth(alias, pass) } // if no callback is passed, auto-login after signing up. - },10); - } - root.get('~@'+alias).once(act.a); + root.get((tmp = "~" + act.pair.pub)).put(act.data); // awesome, now we can actually save the user with their public key as their ID. + root.get("~@" + alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. + setTimeout(function() { + // we should be able to delete this now, right? + cat.ing = false; + cb({ ok: 0, pub: act.pair.pub }); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) + if (noop === cb) { + gun.auth(alias, pass); + } // if no callback is passed, auto-login after signing up. + }, 10); + }; + root.get("~@" + alias).once(act.a); return gun; - } + }; // now that we have created a user, we want to authenticate them! - User.prototype.auth = function(alias, pass, cb, opt){ - var gun = this, cat = (gun._), root = gun.back(-1); - cb = cb || function(){}; - if(cat.ing){ - cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); + User.prototype.auth = function(alias, pass, cb, opt) { + var gun = this, + cat = gun._, + root = gun.back(-1); + cb = cb || function() {}; + if (cat.ing) { + cb({ + err: Gun.log("User is already being created or authenticated!"), + wait: true + }); return gun; } cat.ing = true; opt = opt || {}; - var pair = (alias && (alias.pub || alias.epub))? alias : (pass && (pass.pub || pass.epub))? pass : null; - var act = {}, u; - act.a = function(data){ - if(!data){ return act.b() } - if(!data.pub){ + var pair = + alias && (alias.pub || alias.epub) + ? alias + : pass && (pass.pub || pass.epub) + ? pass + : null; + var act = {}, + u; + act.a = function(data) { + if (!data) { + return act.b(); + } + if (!data.pub) { var tmp = []; - Gun.node.is(data, function(v){ tmp.push(v) }) + Gun.node.is(data, function(v) { + tmp.push(v); + }); return act.b(tmp); } - if(act.name){ return act.f(data) } + if (act.name) { + return act.f(data); + } act.c((act.data = data).auth); - } - act.b = function(list){ - var get = (act.list = (act.list||[]).concat(list||[])).shift(); - if(u === get){ - if(act.name){ return act.err('Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer.') } - return act.err('Wrong user or password.') + }; + act.b = function(list) { + var get = (act.list = (act.list || []).concat(list || [])).shift(); + if (u === get) { + if (act.name) { + return act.err( + "Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer." + ); + } + return act.err("Wrong user or password."); } root.get(get).once(act.a); - } - act.c = function(auth){ - if(u === auth){ return act.b() } - if(Gun.text.is(auth)){ return act.c(Gun.obj.ify(auth)) } // in case of legacy + }; + act.c = function(auth) { + if (u === auth) { + return act.b(); + } + if (Gun.text.is(auth)) { + return act.c(Gun.obj.ify(auth)); + } // in case of legacy SEA.work(pass, (act.auth = auth).s, act.d, act.enc); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. - } - act.d = function(proof){ + }; + act.d = function(proof) { SEA.decrypt(act.auth.ek, proof, act.e, act.enc); - } - act.e = function(half){ - if(u === half){ - if(!act.enc){ // try old format - act.enc = {encode: 'utf8'}; + }; + act.e = function(half) { + if (u === half) { + if (!act.enc) { + // try old format + act.enc = { encode: "utf8" }; return act.c(act.auth); - } act.enc = null; // end backwards + } + act.enc = null; // end backwards return act.b(); } act.half = half; act.f(act.data); - } - act.f = function(data){ - if(!data || !data.pub){ return act.b() } + }; + act.f = function(data) { + if (!data || !data.pub) { + return act.b(); + } var tmp = act.half || {}; - act.g({pub: data.pub, epub: data.epub, priv: tmp.priv, epriv: tmp.epriv}); - } - act.g = function(pair){ + act.g({ + pub: data.pub, + epub: data.epub, + priv: tmp.priv, + epriv: tmp.epriv + }); + }; + act.g = function(pair) { act.pair = pair; - var user = (root._).user, at = (user._); + var user = root._.user, + at = user._; var tmp = at.tag; var upt = at.opt; - at = user._ = root.get('~'+pair.pub)._; + at = user._ = root.get("~" + pair.pub)._; at.opt = upt; // add our credentials in-memory only to our root user instance - user.is = {pub: pair.pub, epub: pair.epub, alias: alias}; + user.is = { pub: pair.pub, epub: pair.epub, alias: alias }; at.sea = act.pair; cat.ing = false; - try{if(pass && !Gun.obj.has(Gun.obj.ify(cat.root.graph['~'+pair.pub].auth), ':')){ opt.shuffle = opt.change = pass; } }catch(e){} // migrate UTF8 & Shuffle! - opt.change? act.z() : cb(at); - if(SEA.window && ((gun.back('user')._).opt||opt).remember){ + try { + if ( + pass && + !Gun.obj.has(Gun.obj.ify(cat.root.graph["~" + pair.pub].auth), ":") + ) { + opt.shuffle = opt.change = pass; + } + } catch (e) {} // migrate UTF8 & Shuffle! + opt.change ? act.z() : cb(at); + if (SEA.window && (gun.back("user")._.opt || opt).remember) { // TODO: this needs to be modular. - try{var sS = {}; - sS = window.sessionStorage; - sS.recall = true; - sS.alias = alias; - sS.tmp = pass; - }catch(e){} + try { + var sS = {}; + sS = window.sessionStorage; + sS.recall = true; + sS.alias = alias; + sS.tmp = pass; + } catch (e) {} } - try{ - (root._).on('auth', at) // TODO: Deprecate this, emit on user instead! Update docs when you do. + try { + root._.on("auth", at); // TODO: Deprecate this, emit on user instead! Update docs when you do. //at.on('auth', at) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. - }catch(e){ + } catch (e) { Gun.log("Your 'auth' callback crashed with:", e); } - } - act.z = function(){ + }; + act.z = function() { // password update so encrypt private key using new pwd + salt act.salt = Gun.text.random(64); // pseudo-random SEA.work(opt.change, act.salt, act.y); - } - act.y = function(proof){ - SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x, {raw:1}); - } - act.x = function(auth){ - act.w(JSON.stringify({ek: auth, s: act.salt})); - } - act.w = function(auth){ - if(opt.shuffle){ // delete in future! - console.log('migrate core account from UTF8 & shuffle'); + }; + act.y = function(proof) { + SEA.encrypt( + { priv: act.pair.priv, epriv: act.pair.epriv }, + proof, + act.x, + { raw: 1 } + ); + }; + act.x = function(auth) { + act.w(JSON.stringify({ ek: auth, s: act.salt })); + }; + act.w = function(auth) { + if (opt.shuffle) { + // delete in future! + console.log("migrate core account from UTF8 & shuffle"); var tmp = Gun.obj.to(act.data); - Gun.obj.del(tmp, '_'); + Gun.obj.del(tmp, "_"); tmp.auth = auth; - root.get('~'+act.pair.pub).put(tmp); + root.get("~" + act.pair.pub).put(tmp); } // end delete - root.get('~'+act.pair.pub).get('auth').put(auth, cb); - } - act.err = function(e){ - var ack = {err: Gun.log(e || 'User cannot be found!')}; + root + .get("~" + act.pair.pub) + .get("auth") + .put(auth, cb); + }; + act.err = function(e) { + var ack = { err: Gun.log(e || "User cannot be found!") }; cat.ing = false; cb(ack); - } - act.plugin = function(name){ - if(!(act.name = name)){ return act.err() } + }; + act.plugin = function(name) { + if (!(act.name = name)) { + return act.err(); + } var tmp = [name]; - if('~' !== name[0]){ - tmp[1] = '~'+name; - tmp[2] = '~@'+name; + if ("~" !== name[0]) { + tmp[1] = "~" + name; + tmp[2] = "~@" + name; } act.b(tmp); - } - if(pair){ + }; + if (pair) { act.g(pair); - } else - if(alias){ - root.get('~@'+alias).once(act.a); - } else - if(!alias && !pass){ + } else if (alias) { + root.get("~@" + alias).once(act.a); + } else if (!alias && !pass) { SEA.name(act.plugin); } return gun; - } - User.prototype.pair = function(){ + }; + User.prototype.pair = function() { console.log("user.pair() IS DEPRECATED AND WILL BE DELETED!!!"); var user = this; - if(!user.is){ return false } + if (!user.is) { + return false; + } return user._.sea; - } - User.prototype.leave = function(opt, cb){ - var gun = this, user = (gun.back(-1)._).user; - if(user){ + }; + User.prototype.leave = function(opt, cb) { + var gun = this, + user = gun.back(-1)._.user; + if (user) { delete user.is; delete user._.is; delete user._.sea; } - if(SEA.window){ - try{var sS = {}; - sS = window.sessionStorage; - delete sS.alias; - delete sS.tmp; - delete sS.recall; - }catch(e){}; + if (SEA.window) { + try { + var sS = {}; + sS = window.sessionStorage; + delete sS.alias; + delete sS.tmp; + delete sS.recall; + } catch (e) {} } return gun; - } + }; // If authenticated user wants to delete his/her account, let's support it! - User.prototype.delete = async function(alias, pass, cb){ - var gun = this, root = gun.back(-1), user = gun.back('user'); + User.prototype.delete = async function(alias, pass, cb) { + var gun = this, + root = gun.back(-1), + user = gun.back("user"); try { - user.auth(alias, pass, function(ack){ - var pub = (user.is||{}).pub; + user.auth(alias, pass, function(ack) { + var pub = (user.is || {}).pub; // Delete user data - user.map().once(function(){ this.put(null) }); + user.map().once(function() { + this.put(null); + }); // Wipe user data from memory user.leave(); - (cb || noop)({ok: 0}); + (cb || noop)({ ok: 0 }); }); } catch (e) { - Gun.log('User.delete failed! Error:', e); + Gun.log("User.delete failed! Error:", e); } return gun; - } - User.prototype.recall = function(opt, cb){ - var gun = this, root = gun.back(-1), tmp; + }; + User.prototype.recall = function(opt, cb) { + var gun = this, + root = gun.back(-1), + tmp; opt = opt || {}; - if(opt && opt.sessionStorage){ - if(SEA.window){ - try{var sS = {}; - sS = window.sessionStorage; - if(sS){ - (root._).opt.remember = true; - ((gun.back('user')._).opt||opt).remember = true; - if(sS.recall || (sS.alias && sS.tmp)){ - root.user().auth(sS.alias, sS.tmp, cb); + if (opt && opt.sessionStorage) { + if (SEA.window) { + try { + var sS = {}; + sS = window.sessionStorage; + if (sS) { + root._.opt.remember = true; + (gun.back("user")._.opt || opt).remember = true; + if (sS.recall || (sS.alias && sS.tmp)) { + root.user().auth(sS.alias, sS.tmp, cb); + } } - } - }catch(e){} + } catch (e) {} } return gun; } @@ -993,81 +1458,125 @@ should expiry be core or a plugin? */ return gun; - } - User.prototype.alive = async function(){ - const gunRoot = this.back(-1) + }; + User.prototype.alive = async function() { + const gunRoot = this.back(-1); try { // All is good. Should we do something more with actual recalled data? - await authRecall(gunRoot) - return gunRoot._.user._ + await authRecall(gunRoot); + return gunRoot._.user._; } catch (e) { - const err = 'No session!' - Gun.log(err) - throw { err } + const err = "No session!"; + Gun.log(err); + throw { err }; } - } - User.prototype.trust = async function(user){ + }; + User.prototype.trust = async function(user) { // TODO: BUG!!! SEA `node` read listener needs to be async, which means core needs to be async too. //gun.get('alice').get('age').trust(bob); if (Gun.is(user)) { - user.get('pub').get((ctx, ev) => { - console.log(ctx, ev) - }) + user.get("pub").get((ctx, ev) => { + console.log(ctx, ev); + }); } - } - User.prototype.grant = function(to, cb){ - console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); - var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); - (async function(){ - var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); - sec = await SEA.decrypt(sec, pair); - if(!sec){ - sec = SEA.random(16).toString(); - enc = await SEA.encrypt(sec, pair); - user.get('trust').get(pair.pub).get(path).put(enc); - } - var pub = to.get('pub').then(); - var epub = to.get('epub').then(); - pub = await pub; epub = await epub; - var dh = await SEA.secret(epub, pair); - enc = await SEA.encrypt(sec, dh); - user.get('trust').get(pub).get(path).put(enc, cb); - }()); + }; + User.prototype.grant = function(to, cb) { + console.log( + "`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!" + ); + var gun = this, + user = gun.back(-1).user(), + pair = user.pair(), + path = ""; + gun.back(function(at) { + if (at.is) { + return; + } + path += at.get || ""; + }); + (async function() { + var enc, + sec = await user + .get("trust") + .get(pair.pub) + .get(path) + .then(); + sec = await SEA.decrypt(sec, pair); + if (!sec) { + sec = SEA.random(16).toString(); + enc = await SEA.encrypt(sec, pair); + user + .get("trust") + .get(pair.pub) + .get(path) + .put(enc); + } + var pub = to.get("pub").then(); + var epub = to.get("epub").then(); + pub = await pub; + epub = await epub; + var dh = await SEA.secret(epub, pair); + enc = await SEA.encrypt(sec, dh); + user + .get("trust") + .get(pub) + .get(path) + .put(enc, cb); + })(); return gun; - } - User.prototype.secret = function(data, cb){ - console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); - var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; - gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); - (async function(){ - var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); - sec = await SEA.decrypt(sec, pair); - if(!sec){ - sec = SEA.random(16).toString(); - enc = await SEA.encrypt(sec, pair); - user.get('trust').get(pair.pub).get(path).put(enc); - } - enc = await SEA.encrypt(data, sec); - gun.put(enc, cb); - }()); + }; + User.prototype.secret = function(data, cb) { + console.log( + "`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!" + ); + var gun = this, + user = gun.back(-1).user(), + pair = user.pair(), + path = ""; + gun.back(function(at) { + if (at.is) { + return; + } + path += at.get || ""; + }); + (async function() { + var enc, + sec = await user + .get("trust") + .get(pair.pub) + .get(path) + .then(); + sec = await SEA.decrypt(sec, pair); + if (!sec) { + sec = SEA.random(16).toString(); + enc = await SEA.encrypt(sec, pair); + user + .get("trust") + .get(pair.pub) + .get(path) + .put(enc); + } + enc = await SEA.encrypt(data, sec); + gun.put(enc, cb); + })(); return gun; - } - module.exports = User - })(USE, './create'); + }; + module.exports = User; + })(USE, "./create"); - ;USE(function(module){ - const SEA = USE('./sea') + USE(function(module) { + const SEA = USE("./sea"); const Gun = SEA.Gun; // After we have a GUN extension to make user registration/login easy, we then need to handle everything else. // We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change) - Gun.on('opt', function(at){ - if(!at.sea){ // only add SEA once per instance, on the "at" context. - at.sea = {own: {}}; - at.on('in', security, at); // now listen to all input data, acting as a firewall. - at.on('out', signature, at); // and output listeners, to encrypt outgoing data. - at.on('node', each, at); + Gun.on("opt", function(at) { + if (!at.sea) { + // only add SEA once per instance, on the "at" context. + at.sea = { own: {} }; + at.on("in", security, at); // now listen to all input data, acting as a firewall. + at.on("out", signature, at); // and output listeners, to encrypt outgoing data. + at.on("node", each, at); } this.to.next(at); // make sure to call the "next" middleware adapter. }); @@ -1085,140 +1594,207 @@ // Here is a problem: Multiple public keys can "claim" any node's ID, so this is dangerous! // This means we should ONLY trust our "friends" (our key ring) public keys, not any ones. // I have not yet added that to SEA yet in this alpha release. That is coming soon, but beware in the meanwhile! - function each(msg){ // TODO: Warning: Need to switch to `gun.on('node')`! Do not use `Gun.on('node'` in your apps! + function each(msg) { + // TODO: Warning: Need to switch to `gun.on('node')`! Do not use `Gun.on('node'` in your apps! // NOTE: THE SECURITY FUNCTION HAS ALREADY VERIFIED THE DATA!!! // WE DO NOT NEED TO RE-VERIFY AGAIN, JUST TRANSFORM IT TO PLAINTEXT. - var to = this.to, vertex = (msg.$._).put, c = 0, d; - Gun.node.is(msg.put, function(val, key, node){ + var to = this.to, + vertex = msg.$._.put, + c = 0, + d; + Gun.node.is(msg.put, function(val, key, node) { // only process if SEA formatted? var tmp = Gun.obj.ify(val) || noop; - if(u !== tmp[':']){ + if (u !== tmp[":"]) { node[key] = SEA.opt.unpack(tmp); return; } - if(!SEA.opt.check(val)){ return } + if (!SEA.opt.check(val)) { + return; + } c++; // for each property on the node - SEA.verify(val, false, function(data){ c--; // false just extracts the plain data. - node[key] = SEA.opt.unpack(data, key, node);; // transform to plain value. - if(d && !c && (c = -1)){ to.next(msg) } + SEA.verify(val, false, function(data) { + c--; // false just extracts the plain data. + node[key] = SEA.opt.unpack(data, key, node); // transform to plain value. + if (d && !c && (c = -1)) { + to.next(msg); + } }); }); - if((d = true) && !c){ to.next(msg) } + if ((d = true) && !c) { + to.next(msg); + } } // signature handles data output, it is a proxy to the security function. - function signature(msg){ - if((msg._||noop).user){ + function signature(msg) { + if ((msg._ || noop).user) { return this.to.next(msg); } var ctx = this.as; - (msg._||(msg._=function(){})).user = ctx.user; + (msg._ || (msg._ = function() {})).user = ctx.user; security.call(this, msg); } // okay! The security function handles all the heavy lifting. // It needs to deal read and write of input and output of system data, account/public key data, and regular data. // This is broken down into some pretty clear edge cases, let's go over them: - function security(msg){ - var at = this.as, sea = at.sea, to = this.to; - if(at.opt.faith && (msg._||noop).faith){ // you probably shouldn't have faith in this! + function security(msg) { + var at = this.as, + sea = at.sea, + to = this.to; + if (at.opt.faith && (msg._ || noop).faith) { + // you probably shouldn't have faith in this! this.to.next(msg); // why do we allow skipping security? I'm very scared about it actually. return; // but so that way storage adapters that already verified something can get performance boost. This was a community requested feature. If anybody finds an exploit with it, please report immediately. It should only be exploitable if you have XSS control anyways, which if you do, you can bypass security regardless of this. } - if(msg.get){ + if (msg.get) { // if there is a request to read data from us, then... - var soul = msg.get['#']; - if(soul){ // for now, only allow direct IDs to be read. - if(typeof soul !== 'string'){ return to.next(msg) } // do not handle lexical cursors. - if('alias' === soul){ // Allow reading the list of usernames/aliases in the system? + var soul = msg.get["#"]; + if (soul) { + // for now, only allow direct IDs to be read. + if (typeof soul !== "string") { + return to.next(msg); + } // do not handle lexical cursors. + if ("alias" === soul) { + // Allow reading the list of usernames/aliases in the system? return to.next(msg); // yes. - } else - if('~@' === soul.slice(0,2)){ // Allow reading the list of public keys associated with an alias? + } else if ("~@" === soul.slice(0, 2)) { + // Allow reading the list of public keys associated with an alias? return to.next(msg); // yes. - } else { // Allow reading everything? + } else { + // Allow reading everything? return to.next(msg); // yes // TODO: No! Make this a callback/event that people can filter on. } } } - if(msg.put){ + if (msg.put) { // potentially parallel async operations!!! - var check = {}, each = {}, u; - each.node = function(node, soul){ - if(Gun.obj.empty(node, '_')){ return check['node'+soul] = 0 } // ignore empty updates, don't reject them. - Gun.obj.map(node, each.way, {soul: soul, node: node}); + var check = {}, + each = {}, + u; + each.node = function(node, soul) { + if (Gun.obj.empty(node, "_")) { + return (check["node" + soul] = 0); + } // ignore empty updates, don't reject them. + Gun.obj.map(node, each.way, { soul: soul, node: node }); }; - each.way = function(val, key){ - var soul = this.soul, node = this.node, tmp; - if('_' === key){ return } // ignore meta data - if('~@' === soul){ // special case for shared system data, the list of aliases. - each.alias(val, key, node, soul); return; - } - if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias. - each.pubs(val, key, node, soul); return; - } - if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. - each.pub(val, key, node, soul, tmp, (msg._||noop).user); return; - } - each.any(val, key, node, soul, (msg._||noop).user); return; - return each.end({err: "No other data allowed!"}); - }; - each.alias = function(val, key, node, soul){ // Example: {_:#~@, ~@alice: {#~@alice}} - if(!val){ return each.end({err: "Data must exist!"}) } // data MUST exist - if('~@'+key === Gun.val.link.is(val)){ return check['alias'+key] = 0 } // in fact, it must be EXACTLY equal to itself - each.end({err: "Mismatching alias."}); // if it isn't, reject. - }; - each.pubs = function(val, key, node, soul){ // Example: {_:#~@alice, ~asdf: {#~asdf}} - if(!val){ return each.end({err: "Alias must exist!"}) } // data MUST exist - if(key === Gun.val.link.is(val)){ return check['pubs'+soul+key] = 0 } // and the ID must be EXACTLY equal to its property - each.end({err: "Alias must match!"}); // that way nobody can tamper with the list of public keys. - }; - each.pub = function(val, key, node, soul, pub, user){ var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}} - if('pub' === key){ - if(val === pub){ return (check['pub'+soul+key] = 0) } // the account MUST match `pub` property that equals the ID of the public key. - return each.end({err: "Account must match!"}); - } - check['user'+soul+key] = 1; - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ - SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ var rel; - if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) } - if(rel = Gun.val.link.is(val)){ - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; - } - node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - check['user'+soul+key] = 0; - each.end({ok: 1}); - }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1}); + each.way = function(val, key) { + var soul = this.soul, + node = this.node, + tmp; + if ("_" === key) { + return; + } // ignore meta data + if ("~@" === soul) { + // special case for shared system data, the list of aliases. + each.alias(val, key, node, soul); return; } - SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel, tmp; + if ("~@" === soul.slice(0, 2)) { + // special case for shared system data, the list of public keys for an alias. + each.pubs(val, key, node, soul); + return; + } + if ( + "~" === soul.slice(0, 1) && + 2 === (tmp = soul.slice(1)).split(".").length + ) { + // special case, account data for a public key. + each.pub(val, key, node, soul, tmp, (msg._ || noop).user); + return; + } + each.any(val, key, node, soul, (msg._ || noop).user); + return; + return each.end({ err: "No other data allowed!" }); + }; + each.alias = function(val, key, node, soul) { + // Example: {_:#~@, ~@alice: {#~@alice}} + if (!val) { + return each.end({ err: "Data must exist!" }); + } // data MUST exist + if ("~@" + key === Gun.val.link.is(val)) { + return (check["alias" + key] = 0); + } // in fact, it must be EXACTLY equal to itself + each.end({ err: "Mismatching alias." }); // if it isn't, reject. + }; + each.pubs = function(val, key, node, soul) { + // Example: {_:#~@alice, ~asdf: {#~asdf}} + if (!val) { + return each.end({ err: "Alias must exist!" }); + } // data MUST exist + if (key === Gun.val.link.is(val)) { + return (check["pubs" + soul + key] = 0); + } // and the ID must be EXACTLY equal to its property + each.end({ err: "Alias must match!" }); // that way nobody can tamper with the list of public keys. + }; + each.pub = function(val, key, node, soul, pub, user) { + var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}} + if ("pub" === key) { + if (val === pub) { + return (check["pub" + soul + key] = 0); + } // the account MUST match `pub` property that equals the ID of the public key. + return each.end({ err: "Account must match!" }); + } + check["user" + soul + key] = 1; + if (Gun.is(msg.$) && user && user.is && pub === user.is.pub) { + SEA.sign( + SEA.opt.prep((tmp = SEA.opt.parse(val)), key, node, soul), + user._.sea, + function(data) { + var rel; + if (u === data) { + return each.end({ err: SEA.err || "Pub signature fail." }); + } + if ((rel = Gun.val.link.is(val))) { + (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; + } + node[key] = JSON.stringify({ + ":": SEA.opt.unpack(data.m), + "~": data.s + }); + check["user" + soul + key] = 0; + each.end({ ok: 1 }); + }, + { check: SEA.opt.pack(tmp, key, node, soul), raw: 1 } + ); + return; + } + SEA.verify(SEA.opt.pack(val, key, node, soul), pub, function(data) { + var rel, tmp; data = SEA.opt.unpack(data, key, node); - if(u === data){ // make sure the signature matches the account it claims to be on. - return each.end({err: "Unverified data."}); // reject any updates that are signed with a mismatched account. + if (u === data) { + // make sure the signature matches the account it claims to be on. + return each.end({ err: "Unverified data." }); // reject any updates that are signed with a mismatched account. } - if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){ + if ((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)) { (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; } - check['user'+soul+key] = 0; - each.end({ok: 1}); + check["user" + soul + key] = 0; + each.end({ ok: 1 }); }); }; - each.any = function(val, key, node, soul, user){ var tmp, pub; - if(!(pub = SEA.opt.pub(soul))){ - if(at.opt.secure){ - each.end({err: "Soul is missing public key at '" + key + "'."}); + each.any = function(val, key, node, soul, user) { + var tmp, pub; + if (!(pub = SEA.opt.pub(soul))) { + if (at.opt.secure) { + each.end({ err: "Soul is missing public key at '" + key + "'." }); return; } // TODO: Ask community if should auto-sign non user-graph data. - check['any'+soul+key] = 1; - at.on('secure', function(msg){ this.off(); - check['any'+soul+key] = 0; - if(at.opt.secure){ msg = null } - each.end(msg || {err: "Data cannot be modified."}); - }).on.on('secure', msg); + check["any" + soul + key] = 1; + at.on("secure", function(msg) { + this.off(); + check["any" + soul + key] = 0; + if (at.opt.secure) { + msg = null; + } + each.end(msg || { err: "Data cannot be modified." }); + }).on.on("secure", msg); //each.end({err: "Data cannot be modified."}); return; } - if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ + if (Gun.is(msg.$) && user && user.is && pub === user.is.pub) { /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){ if((user.is||{}).pub !== p){ return p } }); @@ -1226,81 +1802,139 @@ each.any(val, key, node, soul); return; }*/ - check['any'+soul+key] = 1; - SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ - if(u === data){ return each.end({err: 'My signature fail.'}) } - node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); - check['any'+soul+key] = 0; - each.end({ok: 1}); - }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1}); + check["any" + soul + key] = 1; + SEA.sign( + SEA.opt.prep((tmp = SEA.opt.parse(val)), key, node, soul), + user._.sea, + function(data) { + if (u === data) { + return each.end({ err: "My signature fail." }); + } + node[key] = JSON.stringify({ + ":": SEA.opt.unpack(data.m), + "~": data.s + }); + check["any" + soul + key] = 0; + each.end({ ok: 1 }); + }, + { check: SEA.opt.pack(tmp, key, node, soul), raw: 1 } + ); return; } - check['any'+soul+key] = 1; - SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel; + check["any" + soul + key] = 1; + SEA.verify(SEA.opt.pack(val, key, node, soul), pub, function(data) { + var rel; data = SEA.opt.unpack(data, key, node); - if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski ! - if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){ + if (u === data) { + return each.end({ err: "Mismatched owner on '" + key + "'." }); + } // thanks @rogowski ! + if ((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)) { (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; } - check['any'+soul+key] = 0; - each.end({ok: 1}); + check["any" + soul + key] = 0; + each.end({ ok: 1 }); }); - } - each.end = function(ctx){ // TODO: Can't you just switch this to each.end = cb? - if(each.err){ return } - if((each.err = ctx.err) || ctx.no){ - console.log('NO!', each.err, msg.put); // 451 mistmached data FOR MARTTI + }; + each.end = function(ctx) { + // TODO: Can't you just switch this to each.end = cb? + if (each.err) { return; } - if(!each.end.ed){ return } - if(Gun.obj.map(check, function(no){ - if(no){ return true } - })){ return } - (msg._||{}).user = at.user || security; // already been through firewall, does not need to again on out. + if ((each.err = ctx.err) || ctx.no) { + console.log("NO!", each.err, msg.put); // 451 mistmached data FOR MARTTI + return; + } + if (!each.end.ed) { + return; + } + if ( + Gun.obj.map(check, function(no) { + if (no) { + return true; + } + }) + ) { + return; + } + (msg._ || {}).user = at.user || security; // already been through firewall, does not need to again on out. to.next(msg); }; Gun.obj.map(msg.put, each.node); - each.end({end: each.end.ed = true}); + each.end({ end: (each.end.ed = true) }); return; // need to manually call next after async. } to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols). } - SEA.opt.pub = function(s){ - if(!s){ return } - s = s.split('~'); - if(!s || !(s = s[1])){ return } - s = s.split('.'); - if(!s || 2 > s.length){ return } - s = s.slice(0,2).join('.'); - return s; - } - SEA.opt.prep = function(d,k, n,s){ // prep for signing - return {'#':s,'.':k,':':SEA.opt.parse(d),'>':Gun.state.is(n, k)}; - } - SEA.opt.pack = function(d,k, n,s){ // pack for verifying - if(SEA.opt.check(d)){ return d } - var meta = (Gun.obj.ify(d)||noop), sig = meta['~']; - return sig? {m: {'#':s,'.':k,':':meta[':'],'>':Gun.state.is(n, k)}, s: sig} : d; - } - SEA.opt.unpack = function(d, k, n){ var tmp; - if(u === d){ return } - if(d && (u !== (tmp = d[':']))){ return tmp } - if(!k || !n){ return } - if(d === n[k]){ return d } - if(!SEA.opt.check(n[k])){ return d } - var soul = Gun.node.soul(n), s = Gun.state.is(n, k); - if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){ - return d[2]; + SEA.opt.pub = function(s) { + if (!s) { + return; } - if(s < SEA.opt.shuffle_attack){ + s = s.split("~"); + if (!s || !(s = s[1])) { + return; + } + s = s.split("."); + if (!s || 2 > s.length) { + return; + } + s = s.slice(0, 2).join("."); + return s; + }; + SEA.opt.prep = function(d, k, n, s) { + // prep for signing + return { "#": s, ".": k, ":": SEA.opt.parse(d), ">": Gun.state.is(n, k) }; + }; + SEA.opt.pack = function(d, k, n, s) { + // pack for verifying + if (SEA.opt.check(d)) { return d; } - } + var meta = Gun.obj.ify(d) || noop, + sig = meta["~"]; + return sig + ? { + m: { "#": s, ".": k, ":": meta[":"], ">": Gun.state.is(n, k) }, + s: sig + } + : d; + }; + SEA.opt.unpack = function(d, k, n) { + var tmp; + if (u === d) { + return; + } + if (d && u !== (tmp = d[":"])) { + return tmp; + } + if (!k || !n) { + return; + } + if (d === n[k]) { + return d; + } + if (!SEA.opt.check(n[k])) { + return d; + } + var soul = Gun.node.soul(n), + s = Gun.state.is(n, k); + if ( + d && + 4 === d.length && + soul === d[0] && + k === d[1] && + fl(s) === fl(d[3]) + ) { + return d[2]; + } + if (s < SEA.opt.shuffle_attack) { + return d; + } + }; SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019 - var noop = function(){}, u; + var noop = function() {}, + u; var fl = Math.floor; // TODO: Still need to fix inconsistent state issue. var rel_is = Gun.val.rel.is; // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible. - - })(USE, './index'); -}()); \ No newline at end of file + })(USE, "./index"); +})(); From 6af5b6c2ac84c24b340f0c52051c51087a3e74a8 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 10 Sep 2019 14:40:34 -0700 Subject: [PATCH 07/19] fix SOME of RAD due to GUN queue growing too deep --- gun.js | 29 +++++++++++++++++++---------- gun.min.js | 2 +- lib/radisk.js | 34 ++++++++++++++++++++-------------- lib/radix.js | 14 ++++++++++---- lib/store.js | 3 --- src/put.js | 3 +-- src/root.js | 2 ++ test/common.js | 1 - test/rad/rad.js | 11 +++++++++-- 9 files changed, 62 insertions(+), 37 deletions(-) diff --git a/gun.js b/gun.js index fe857936..8c2b71f5 100644 --- a/gun.js +++ b/gun.js @@ -1235,7 +1235,7 @@ gun = gun.$; } else if(key instanceof Function){ - if(true === cb){ return soul(this, key, cb, as) } + if(true === cb){ return soul(this, key, cb, as), this } gun = this; var at = gun._, root = at.root, tmp = root.now, ev; as = cb || {}; @@ -1292,15 +1292,22 @@ } function soul(gun, cb, opt, as){ var cat = gun._, acks = 0, tmp; - if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat), gun } - gun.get(function(msg, ev){ + if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat) } + if(cat.jam){ return cat.jam.push([cb, as]) } + cat.jam = [[cb,as]]; + gun.get(function(msg, eve){ if(u === msg.put && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks < tmp){ return; } - ev.rid(msg); + eve.rid(msg); var at = ((at = msg.$) && at._) || {}; - tmp = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put) || at.dub; - cb(tmp, as, msg, ev); + tmp = cat.jam; Gun.obj.del(cat, 'jam'); + Gun.obj.map(tmp, function(as, cb){ + cb = as[0]; as = as[1]; + if(!cb){ return } + var id = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put) || at.dub; + cb(id, as, msg, eve); + }); }, {out: {get: {'.':true}}}); return gun; } @@ -1361,9 +1368,9 @@ Gun.chain.put = function(data, cb, as){ // #soul.has=value>state // ~who#where.where=what>when@was - // TODO: BUG! Put probably cannot handle plural chains! + // TODO: BUG! Put probably cannot handle plural chains! `!as` is quickfix test. var gun = this, at = (gun._), root = at.root.$, ctx = root._, M = 100, tmp; - if(!ctx.puta){ if(tmp = ctx.puts){ if(tmp > M){ // without this, when synchronous, writes to a 'not found' pile up, when 'not found' resolves it recursively calls `put` which incrementally resolves each write. Stack overflow limits can be as low as 10K, so this limit is hardcoded to 1% of 10K. + /*if(!ctx.puta && !as){ if(tmp = ctx.puts){ if(tmp > M){ // without this, when synchronous, writes to a 'not found' pile up, when 'not found' resolves it recursively calls `put` which incrementally resolves each write. Stack overflow limits can be as low as 10K, so this limit is hardcoded to 1% of 10K. (ctx.stack || (ctx.stack = [])).push([gun, data, cb, as]); if(ctx.puto){ return } ctx.puto = setTimeout(function drain(){ @@ -1373,7 +1380,7 @@ ctx.stack = ctx.puts = ctx.puto = null; }, 0); return gun; - } ++ctx.puts } else { ctx.puts = 1 } } + } ++ctx.puts } else { ctx.puts = 1 } }*/ as = as || {}; as.data = data; as.via = as.$ = as.via || as.$ || gun; @@ -1496,6 +1503,7 @@ ref = ref.get(path[i]); } if(is){ ref = v } + //if(as.not){ (ref._).dub = Gun.text.random() } // This might optimize stuff? Maybe not needed anymore. Make sure it doesn't introduce bugs. var id = (ref._).dub; if(id || (id = Gun.node.soul(at.obj))){ ref.back(-1).get(id); @@ -1556,6 +1564,7 @@ if(at.link || at.soul){ return at.link || at.soul } as.data = obj_put({}, at.get, as.data); }); + as.not = true; // maybe consider this? } tmp = tmp || at.soul || at.link || at.dub;// || at.get; at = tmp? (at.root.$.get(tmp)._) : at; @@ -1815,7 +1824,7 @@ // See the next 'opt' code below for actual saving of data. var ev = this.to, opt = root.opt; if(root.once){ return ev.next(root) } - //if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! + if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! // actually, this doesn't help, per @go1dfish 's observation. Disabling for now, will need better solution later. opt.prefix = opt.file || 'gun/'; var gap = Gun.obj.ify(store.getItem('gap/'+opt.prefix)) || {}; var empty = Gun.obj.empty, id, to, go; diff --git a/gun.min.js b/gun.min.js index 51508f79..bf1a6552 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var b=(t=t||{}).console||{log:function(){}};function _(o,t){return t?require(o):o.slice?_[e(o)]:function(t,n){o(t={exports:{}}),_[e(n)]=t.exports};function e(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var o=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||e===n["="]&&(o=n["*"]||n[">"]||n["<"],t.slice(0,(o||"").length)===o||e===n["*"]&&(e!==n[">"]&&e!==n["<"]?t>=n[">"]&&t<=n["<"]:e!==n[">"]&&t>=n[">"]||e!==n["<"]&&t<=n["<"])))},p.list={is:function(t){return t instanceof Array}},p.list.slit=Array.prototype.slice,p.list.sort=function(o){return function(t,n){return t&&n?(t=t[o])<(n=n[o])?-1:n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=(t||{})[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.is(t,this.fn,this.as))return!0;this.cb&&(o.n=t,o.as=this.as,this.cb.call(o.as,t,n,o))}function o(t){t&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(t,n){var o;return(o=function(t,n){var o,e=t.seen,i=e.length;for(;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}(t,n))?o:(n.env=t,n.soul=i,c.ify(n.obj,e,n)&&(n.link=n.link||f.link.ify(c.soul(n.node)),n.obj!==t.shell&&(t.graph[f.link.is(n.link)]=n.node)),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.link._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.link.is(r.link)),r.link=r.link||f.link.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function i(t){var n=this,o=f.link.is(n.link),e=n.env.graph;n.link=n.link||f.link.ify(t),n.link[f.link._]=t,n.node&&n.node[c._]&&(n.node[c._][f.link._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(t=r.call(i.as||{},t,n,o),n,o,e,i):(i.err="Invalid value at '"+e.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}r.ify=function(t,n,o){var e={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(e.link=f.link.ify(n.soul)),n.shell=(o||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.link.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.link._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./graph"),_(function(t){_("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),o}}})(_,"./ask"),_(function(t){var r=_("./type");var a=r.time.is;t.exports=function(e){var i={s:{}};return e=e||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var o=i.s[t]||(i.s[t]={});return o.was=a(),n&&(o.pass=!0),i.to||(i.to=setTimeout(function(){var o=a();r.obj.map(i.s,function(t,n){t&&e.age>o-t.was||r.obj.del(i.s,n)}),i.to=null},e.age+9)),o},i}})(_,"./dup"),_(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=_("./type");n.obj.to(n,c),c.HAM=_("./HAM"),c.val=_("./val"),c.node=_("./node"),c.state=_("./state"),c.graph=_("./graph"),c.on=_("./onto"),c.ask=_("./ask"),c.dup=_("./dup"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(9)),(n=i.dup).check(o)?e.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(o),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),e.out||(t.out=a,i.on("out",t)))}c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n}}(),function(){function i(t,n,o,e){var i=this,r=c.state.is(o,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=i.graph[e]||v,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[e]=c.state.to(o,n,i.put[e]),(i.diff||(i.diff={}))[e]=c.state.to(o,n,i.diff[e]),i.souls[e]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var o=this,e=o.$._,i=(e.next||v)[n];if(!i){if(!(e.opt||v).super)return void(o.souls[n]=!1);i=o.$.get(n)._}var r=o.map[n]={put:t,get:n,$:i.$},a={ctx:o,msg:r};o.async=!!e.tag.node,o.ack&&(r["@"]=o.ack),h(t,u,a),o.async&&(o.and||e.on("node",function(t){this.to.next(t),t===o.map[t.get]&&(o.souls[t.get]=!1,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(o.map,f,o)))}),o.and=!0,e.on("node",r))}function u(t,n){var o=this.ctx,e=o.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;e[r]=c.state.to(a,n,e[r]),o.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var o=this.put,e=this.$._;e.put=c.state.to(o,n,e.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}c.on.put=function(t,n){var o=n._,e={$:n,graph:o.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:o,stop:{}};if(c.graph.is(t.put,null,i,e)||(e.err="Error: Invalid graph!"),e.err)return o.on("in",{"@":t["#"],err:c.log(e.err)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get,i=e[d],r=o.graph[i],a=e[g],u=(o.next||(o.next={}))[i];if(!r)return o.on("get",t);if(a){if("string"!=typeof a||!l(r,a))return o.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||v).ack,o.on("in",{"@":t["#"],how:"mem",put:r,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return s(t)||(t={}),s(n.opt)||(n.opt=t),r(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){(n={}).id=n.url=t,o(t,n)}),s(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},h(t,function t(n,o){!l(this,o)||i.is(n)||a.empty(n)?this[o]=n:h(n,t,this[o])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return f()+u(12)},this};var e=c.list.is,i=c.text,r=i.is,u=i.random,a=c.obj,s=a.is,l=a.has,p=a.to,h=a.map,f=(a.copy,c.state.lex),d=c.val.link._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,o){return(o=c.log.once)[t]=o[t]||0,o[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==o&&(o.exports=c)}catch(t){}t.exports=c})(_,"./root"),_(function(t){var u=_("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var o=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var e=0,i=t.length,r=o;e(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),o=0,e=n.root.now;u.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?u.to(i,n.root.mum):i,n.root.now=e},r),r.res&&r.res())}function n(t,n){if(t)return!0}function l(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||e)(function(){for(var t=a.path,n=u.ref,o=(u.opt,0),e=t.length;o .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(e.batch||1e3))return f();i||(i=setTimeout(f,e.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,o,e){s[e]=Gun.state.to(o,n,s[e])},f=function(t){var o;u=0,clearTimeout(i),i=!1;var n=a;a={},t&&(s=t);try{p.setItem(e.prefix,JSON.stringify(s))}catch(t){Gun.log(o=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),r.on("localStorage:error",{err:o,file:e.prefix,flush:s,retry:f})}(o||Gun.obj.empty(e.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");!function(){d.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<"])&&(o._.to=d.obj.map(r.split(","),f)),o.dam?void((r=c.hear[o.dam])&&r(o,n,s)):void s.on("in",o)}}else{try{o=JSON.parse(t)}catch(t){l.log("DAM JSON parse error",t)}if(!o)return;for(var a,u=0;a=o[u++];)c.hear(a,n)}}};var f=function(t,n,o){o(t,!0)};function h(n,o){try{var t=o.wire;o.say?o.say(n):t.send&&t.send(n),c.say.d+=n.length||0,++c.say.c}catch(t){(o.queue=o.queue||[]).push(n)}}c.hear.c=c.hear.d=0,function(){var u;function s(t){c.say(u,t)}function f(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return l.log("DAM JSON stringify error",t)}n&&h(n,t)}}c.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var o,e,i,r,a=t._||(t._=function(){});if((o=t["#"])||(o=t["#"]=d.text.random(9)),(e=t["##"])||void 0===t.put||(e=t["##"]=d.obj.hash(t.put)),!(r=a.raw)&&(r=a.raw=c.raw(t),e&&(i=t["@"])&&(p.track(i+e).it=t,i=(p.s[i]||!0).it))){if(e===i["##"])return!1;i["##"]=e}if(p.track(o).it=t,n||(n=(i=p.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via)),!n&&c.way)return c.way(t);if(!n||!n.id)return u=t,!!d.obj.is(n||l.peers)&&void d.obj.map(n||l.peers,s);if(!n.wire&&c.wire&&c.wire(n),o!==n.last){if(n.last=o,n===a.via)return!1;if((i=a.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=l.pack)return void n.batch.push(r);f(n)}n.batch=[],setTimeout(function(){f(n)},l.gap),h(r,n)}},c.say.c=c.say.d=0}(),function(){c.raw=function(t){if(!t)return"";var n,o=t._||{};if(n=o.raw)return n;if("string"==typeof t)return t;if(!t.dam){var e=0,i=[];d.obj.map(l.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++e)return!0}),1<"]=i.join())}var r=a(t);return o&&(o.raw=r),r};var a=JSON.stringify}(),c.hi=function(n){var t=n.wire||{};n.id?l.peers[n.url||n.id]=n:(t=n.id=n.id||d.text.random(9),c.say({dam:"?"},l.peers[t]=n)),n.met=n.met||+new Date,t.hied||s.on(t.hied="hi",n),t=n.queue,n.queue=[],d.obj.map(t,function(t){h(t,n)})},c.bye=function(t){s.on("bye",t);var n=+new Date;n-=t.met||n,c.bye.time=((c.bye.time||n)+n)/2},c.hear["!"]=function(t,n){l.log("Error:",t.err)},c.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):c.say({dam:"?",pid:l.pid,"@":t["#"]},n)},s.on("create",function(t){t.opt.pid=t.opt.pid||d.text.random(9),this.to.next(t),t.on("out",c.say)}),s.on("bye",function(t,n){t=l.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),d.obj.del(l.peers,t.id),t.wire=null});var i={};return s.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},l.lack||9e3))}),s.on("hi",function(o,e){this.to.next(o),(e=o.url)&&i[e]&&(delete i[e],d.obj.map(s.next,function(t,n){(e={})[n]=s.graph[n],c.say({"##":d.obj.hash(e),get:{"#":n}},o)}))}),c}}catch(t){}})(_,"./adapters/mesh"),_(function(t){var f=_("../index");f.Mesh=_("./mesh"),f.on("opt",function(t){this.to.next(t);var e=t.opt;if(!t.once&&!1!==e.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=e.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(o){e.WebSocket=o;var i=e.mesh=e.mesh||f.Mesh(t);i.wire||e.wire;i.wire=e.wire=u;var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return o&&o(n);var t=n.url.replace("http","ws"),o=n.wire=new e.WebSocket(t);return o.onclose=function(){e.mesh.bye(n),s(n)},o.onerror=function(t){s(n)},o.onopen=function(){e.mesh.hi(n)},o.onmessage=function(t){t&&e.mesh.hear(t.data||t,n)},o}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||e.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})(_,"./adapters/websocket")}(); \ No newline at end of file +!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var b=(t=t||{}).console||{log:function(){}};function _(o,t){return t?require(o):o.slice?_[e(o)]:function(t,n){o(t={exports:{}}),_[e(n)]=t.exports};function e(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var o=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||e===n["="]&&(o=n["*"]||n[">"]||n["<"],t.slice(0,(o||"").length)===o||e===n["*"]&&(e!==n[">"]&&e!==n["<"]?t>=n[">"]&&t<=n["<"]:e!==n[">"]&&t>=n[">"]||e!==n["<"]&&t<=n["<"])))},p.list={is:function(t){return t instanceof Array}},p.list.slit=Array.prototype.slice,p.list.sort=function(o){return function(t,n){return t&&n?(t=t[o])<(n=n[o])?-1:n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=(t||{})[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.is(t,this.fn,this.as))return!0;this.cb&&(o.n=t,o.as=this.as,this.cb.call(o.as,t,n,o))}function o(t){t&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(t,n){var o;return(o=function(t,n){var o,e=t.seen,i=e.length;for(;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}(t,n))?o:(n.env=t,n.soul=i,c.ify(n.obj,e,n)&&(n.link=n.link||f.link.ify(c.soul(n.node)),n.obj!==t.shell&&(t.graph[f.link.is(n.link)]=n.node)),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.link._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.link.is(r.link)),r.link=r.link||f.link.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function i(t){var n=this,o=f.link.is(n.link),e=n.env.graph;n.link=n.link||f.link.ify(t),n.link[f.link._]=t,n.node&&n.node[c._]&&(n.node[c._][f.link._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(t=r.call(i.as||{},t,n,o),n,o,e,i):(i.err="Invalid value at '"+e.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}r.ify=function(t,n,o){var e={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(e.link=f.link.ify(n.soul)),n.shell=(o||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.link.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.link._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./graph"),_(function(t){_("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),o}}})(_,"./ask"),_(function(t){var r=_("./type");var a=r.time.is;t.exports=function(e){var i={s:{}};return e=e||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var o=i.s[t]||(i.s[t]={});return o.was=a(),n&&(o.pass=!0),i.to||(i.to=setTimeout(function(){var o=a();r.obj.map(i.s,function(t,n){t&&e.age>o-t.was||r.obj.del(i.s,n)}),i.to=null},e.age+9)),o},i}})(_,"./dup"),_(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=_("./type");n.obj.to(n,c),c.HAM=_("./HAM"),c.val=_("./val"),c.node=_("./node"),c.state=_("./state"),c.graph=_("./graph"),c.on=_("./onto"),c.ask=_("./ask"),c.dup=_("./dup"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(9)),(n=i.dup).check(o)?e.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(o),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),e.out||(t.out=a,i.on("out",t)))}c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n}}(),function(){function i(t,n,o,e){var i=this,r=c.state.is(o,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=i.graph[e]||v,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[e]=c.state.to(o,n,i.put[e]),(i.diff||(i.diff={}))[e]=c.state.to(o,n,i.diff[e]),i.souls[e]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var o=this,e=o.$._,i=(e.next||v)[n];if(!i){if(!(e.opt||v).super)return void(o.souls[n]=!1);i=o.$.get(n)._}var r=o.map[n]={put:t,get:n,$:i.$},a={ctx:o,msg:r};o.async=!!e.tag.node,o.ack&&(r["@"]=o.ack),h(t,u,a),o.async&&(o.and||e.on("node",function(t){this.to.next(t),t===o.map[t.get]&&(o.souls[t.get]=!1,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(o.map,f,o)))}),o.and=!0,e.on("node",r))}function u(t,n){var o=this.ctx,e=o.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;e[r]=c.state.to(a,n,e[r]),o.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var o=this.put,e=this.$._;e.put=c.state.to(o,n,e.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}c.on.put=function(t,n){var o=n._,e={$:n,graph:o.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:o,stop:{}};if(c.graph.is(t.put,null,i,e)||(e.err="Error: Invalid graph!"),e.err)return o.on("in",{"@":t["#"],err:c.log(e.err)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get,i=e[d],r=o.graph[i],a=e[g],u=(o.next||(o.next={}))[i];if(!r)return o.on("get",t);if(a){if("string"!=typeof a||!l(r,a))return o.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||v).ack,o.on("in",{"@":t["#"],how:"mem",put:r,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return s(t)||(t={}),s(n.opt)||(n.opt=t),r(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){(n={}).id=n.url=t,o(t,n)}),s(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},h(t,function t(n,o){!l(this,o)||i.is(n)||a.empty(n)?this[o]=n:n&&n.constructor!==Object&&!e(n)||h(n,t,this[o])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return f()+u(12)},this};var e=c.list.is,i=c.text,r=i.is,u=i.random,a=c.obj,s=a.is,l=a.has,p=a.to,h=a.map,f=(a.copy,c.state.lex),d=c.val.link._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,o){return(o=c.log.once)[t]=o[t]||0,o[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==o&&(o.exports=c)}catch(t){}t.exports=c})(_,"./root"),_(function(t){var u=_("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var o=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var e=0,i=t.length,r=o;e(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),o=0,e=n.root.now;u.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?u.to(i,n.root.mum):i,n.root.now=e},r),r.res&&r.res())}function n(t,n){if(t)return!0}function l(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||e)(function(){for(var t=a.path,n=u.ref,o=(u.opt,0),e=t.length;o .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(e.batch||1e3))return f();i||(i=setTimeout(f,e.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,o,e){s[e]=Gun.state.to(o,n,s[e])},f=function(t){var o;u=0,clearTimeout(i),i=!1;var n=a;a={},t&&(s=t);try{p.setItem(e.prefix,JSON.stringify(s))}catch(t){Gun.log(o=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),r.on("localStorage:error",{err:o,file:e.prefix,flush:s,retry:f})}(o||Gun.obj.empty(e.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");!function(){d.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<"])&&(o._.to=d.obj.map(r.split(","),f)),o.dam?void((r=c.hear[o.dam])&&r(o,n,s)):void s.on("in",o)}}else{try{o=JSON.parse(t)}catch(t){l.log("DAM JSON parse error",t)}if(!o)return;for(var a,u=0;a=o[u++];)c.hear(a,n)}}};var f=function(t,n,o){o(t,!0)};function h(n,o){try{var t=o.wire;o.say?o.say(n):t.send&&t.send(n),c.say.d+=n.length||0,++c.say.c}catch(t){(o.queue=o.queue||[]).push(n)}}c.hear.c=c.hear.d=0,function(){var u;function s(t){c.say(u,t)}function f(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return l.log("DAM JSON stringify error",t)}n&&h(n,t)}}c.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var o,e,i,r,a=t._||(t._=function(){});if((o=t["#"])||(o=t["#"]=d.text.random(9)),(e=t["##"])||void 0===t.put||(e=t["##"]=d.obj.hash(t.put)),!(r=a.raw)&&(r=a.raw=c.raw(t),e&&(i=t["@"])&&(p.track(i+e).it=t,i=(p.s[i]||!0).it))){if(e===i["##"])return!1;i["##"]=e}if(p.track(o).it=t,n||(n=(i=p.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via)),!n&&c.way)return c.way(t);if(!n||!n.id)return u=t,!!d.obj.is(n||l.peers)&&void d.obj.map(n||l.peers,s);if(!n.wire&&c.wire&&c.wire(n),o!==n.last){if(n.last=o,n===a.via)return!1;if((i=a.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=l.pack)return void n.batch.push(r);f(n)}n.batch=[],setTimeout(function(){f(n)},l.gap),h(r,n)}},c.say.c=c.say.d=0}(),function(){c.raw=function(t){if(!t)return"";var n,o=t._||{};if(n=o.raw)return n;if("string"==typeof t)return t;if(!t.dam){var e=0,i=[];d.obj.map(l.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++e)return!0}),1<"]=i.join())}var r=a(t);return o&&(o.raw=r),r};var a=JSON.stringify}(),c.hi=function(n){var t=n.wire||{};n.id?l.peers[n.url||n.id]=n:(t=n.id=n.id||d.text.random(9),c.say({dam:"?"},l.peers[t]=n)),n.met=n.met||+new Date,t.hied||s.on(t.hied="hi",n),t=n.queue,n.queue=[],d.obj.map(t,function(t){h(t,n)})},c.bye=function(t){s.on("bye",t);var n=+new Date;n-=t.met||n,c.bye.time=((c.bye.time||n)+n)/2},c.hear["!"]=function(t,n){l.log("Error:",t.err)},c.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):c.say({dam:"?",pid:l.pid,"@":t["#"]},n)},s.on("create",function(t){t.opt.pid=t.opt.pid||d.text.random(9),this.to.next(t),t.on("out",c.say)}),s.on("bye",function(t,n){t=l.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),d.obj.del(l.peers,t.id),t.wire=null});var i={};return s.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},l.lack||9e3))}),s.on("hi",function(o,e){this.to.next(o),(e=o.url)&&i[e]&&(delete i[e],d.obj.map(s.next,function(t,n){(e={})[n]=s.graph[n],c.say({"##":d.obj.hash(e),get:{"#":n}},o)}))}),c}}catch(t){}})(_,"./adapters/mesh"),_(function(t){var f=_("../index");f.Mesh=_("./mesh"),f.on("opt",function(t){this.to.next(t);var e=t.opt;if(!t.once&&!1!==e.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=e.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(o){e.WebSocket=o;var i=e.mesh=e.mesh||f.Mesh(t);i.wire||e.wire;i.wire=e.wire=u;var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return o&&o(n);var t=n.url.replace("http","ws"),o=n.wire=new e.WebSocket(t);return o.onclose=function(){e.mesh.bye(n),s(n)},o.onerror=function(t){s(n)},o.onopen=function(){e.mesh.hi(n)},o.onmessage=function(t){t&&e.mesh.hear(t.data||t,n)},o}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||e.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})(_,"./adapters/websocket")}(); \ No newline at end of file diff --git a/lib/radisk.js b/lib/radisk.js index 2e0b6a24..5f6a5f09 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -14,12 +14,12 @@ opt.chunk = opt.chunk || (1024 * 1024 * 10); // 10MB opt.code = opt.code || {}; opt.code.from = opt.code.from || '!'; - //opt.jsonify = true; // TODO: REMOVE!!!! + //opt.jsonify = true; if(opt.jsonify){ console.log("JSON RAD!!!") } // TODO: REMOVE!!!! function ename(t){ return encodeURIComponent(t).replace(/\*/g, '%2A') } function atomic(v){ return u !== v && (!v || 'object' != typeof v) } var map = Gun.obj.map; - var LOG = false; + var LOG = false;//true; if(!opt.store){ return opt.log("ERROR: Radisk needs `opt.store` interface with `{get: fn, put: fn (, list: fn)}`!"); @@ -83,12 +83,13 @@ r.batch = Radix(); r.batch.acks = []; r.batch.ed = 0; - //var id = Gun.text.random(2), S = (+new Date); console.log("<<<<<<<<<<<<", id); + //console.debug(99); var ID = Gun.text.random(2), S = (+new Date); console.log("[[[[[[[[", ID, batch.acks.length); r.save(batch, function(err, ok){ if(++i > 1){ opt.log('RAD ERR: Radisk has callbacked multiple times, please report this as a BUG at github.com/amark/gun/issues ! ' + i); return } if(err){ opt.log('err', err) } - //console.log(">>>>>>>>>>>>", id, ((+new Date) - S), batch.acks.length); + //console.debug(99); var TMP; console.log("]]]]]]]]", ID, batch.acks.length, (TMP = +new Date) - S, 'more?', thrash.more); map(batch.acks, function(cb){ cb(err, ok) }); + //console.log("][", +new Date - TMP, thrash.more); thrash.at = null; thrash.ing = false; if(thrash.more){ thrash() } @@ -171,9 +172,9 @@ } f.write = function(){ var tmp = ename(file); - var start; LOG && (start = (+new Date)); // comment this out! + var start; LOG && (start = +new Date); // comment this out! opt.store.put(tmp, f.text, function(err){ - LOG && console.log("wrote JSON in", (+new Date) - start); // comment this out! + LOG && console.log("wrote to disk in", (+new Date) - start, tmp); // comment this out! if(err){ return cb(err) } r.list.add(tmp, cb); }); @@ -202,10 +203,10 @@ r.write.jsonify = function(f, file, rad, cb, o){ var raw; - var start; LOG && (start = (+new Date)); // comment this out! + var start; LOG && (start = +new Date); // comment this out! try{raw = JSON.stringify(rad.$); }catch(e){ return cb("Record too big!") } - LOG && console.log("stringified JSON in", (+new Date) - start); // comment this out! + LOG && console.log("stringified JSON in", +new Date - start); // comment this out! if(opt.chunk < raw.length && !o.force){ if(Radix.map(rad, f.each, true)){ return } } @@ -220,7 +221,7 @@ var sub = Radix(); Radix.map(tree, function(v,k){ sub(k,v); - }, o) + }, o); return sub(''); } @@ -266,7 +267,7 @@ } g.ack = function(as){ if(!as.ack){ return } - var tmp = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(tmp), o), last = rad.last; + var tmp = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(tmp), o), last = rad.last || Radix.map(rad, rev, revo); o.parsed = (o.parsed || 0) + (info.parsed||0); o.chunks = (o.chunks || 0) + 1; if(!o.some){ o.some = (u !== data) } @@ -283,6 +284,8 @@ if(o.reverse){ g.lex.reverse = true } r.list(g.lex); } + function rev(a,b){ return b } + var revo = {reverse: true}; }()); ;(function(){ @@ -299,6 +302,7 @@ var p = function Parse(){}, info = {}; p.disk = Radix(); p.read = function(err, data){ var tmp; + LOG && console.log('read disk in', +new Date - start, ename(file)); // keep this commented out in delete Q[file]; if((p.err = err) || (p.not = !data)){ return map(q, p.ack); @@ -315,12 +319,12 @@ } info.parsed = data.length; - var start; LOG && (start = (+new Date)); // keep this commented out in production! + LOG && (start = +new Date); // keep this commented out in production! if(opt.jsonify){ // temporary testing idea try{ var json = JSON.parse(data); p.disk.$ = json; - LOG && console.log('parsed JSON in', (+new Date) - start); // keep this commented out in production! + LOG && console.log('parsed JSON in', +new Date - start); // keep this commented out in production! map(q, p.ack); return; }catch(e){ tmp = e } @@ -329,7 +333,7 @@ return map(q, p.ack); } } - var start; LOG && (start = (+new Date)); // keep this commented out in production! + LOG && (start = +new Date); // keep this commented out in production! var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; @@ -352,7 +356,7 @@ if(u !== k && u !== v){ p.disk(pre.join(''), v) } tmp = p.split(tmp[2]); } - LOG && console.log('parsed JSON in', (+new Date) - start); // keep this commented out in production! + LOG && console.log('parsed RAD in', +new Date - start); // keep this commented out in production! //cb(err, p.disk); map(q, p.ack); }; @@ -372,6 +376,7 @@ if(p.err || p.not){ return cb(p.err, u, info) } cb(u, p.disk, info); } + var start; LOG && (start = +new Date); // keep this commented out in production! if(raw){ return p.read(null, raw) } opt.store.get(ename(file), p.read); } @@ -504,6 +509,7 @@ } else { var Gun = require('../gun'); var Radix = require('./radix'); + //var Radix = require('./radix2'); Radisk = require('./radisk2'); try{ module.exports = Radisk }catch(e){} } diff --git a/lib/radix.js b/lib/radix.js index 8a5b59a0..e4533f32 100644 --- a/lib/radix.js +++ b/lib/radix.js @@ -54,10 +54,10 @@ Radix.map = function map(radix, cb, opt, pre){ pre = pre || []; var t = ('function' == typeof radix)? radix.$ || {} : radix; if(!t){ return } - var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort; + var keys = (t[_]||no).sort || (t[_] = function $(){ $.sort = Object.keys(t).sort(); return $ }()).sort, rev; //var keys = Object.keys(t).sort(); opt = (true === opt)? {branch: true} : (opt || {}); - if(opt.reverse){ keys = keys.slice().reverse() } + if(rev = opt.reverse){ keys = keys.slice().reverse() } var start = opt.start, end = opt.end; var i = 0, l = keys.length; for(;i < l; i++){ var key = keys[i], tree = t[key], tmp, p, pt; @@ -66,6 +66,10 @@ pt = p.join(''); if(u !== start && pt < (start||'').slice(0,pt.length)){ continue } if(u !== end && (end || '\uffff') < pt){ continue } + if(rev){ // children must be checked first when going in reverse. + tmp = map(tree, cb, opt, p); + if(u !== tmp){ return tmp } + } if(u !== (tmp = tree[''])){ tmp = cb(tmp, pt, key, pre); if(u !== tmp){ return tmp } @@ -75,8 +79,10 @@ if(u !== tmp){ return tmp } } pre = p; - tmp = map(tree, cb, opt, pre); - if(u !== tmp){ return tmp } + if(!rev){ + tmp = map(tree, cb, opt, pre); + if(u !== tmp){ return tmp } + } pre.pop(); } }; diff --git a/lib/store.js b/lib/store.js index c58aa256..56c4dcda 100644 --- a/lib/store.js +++ b/lib/store.js @@ -67,14 +67,12 @@ Gun.on('create', function(root){ o.limit = (tmp <= (o.pack || (1000 * 100)))? tmp : 1; } if(has['-'] || (soul||{})['-']){ o.reverse = true } - //console.log("RAD get:", key, o); var start = (+new Date); // STATS! // console.log("GET!", id, JSON.stringify(key)); rad(key||'', function(err, data, o){ try{opt.store.stats.get.time[statg % 50] = (+new Date) - start; ++statg; opt.store.stats.get.count++; if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! - //console.log("RAD gat:", err, data, o); if(data){ if(typeof data !== 'string'){ if(o.atom){ @@ -85,7 +83,6 @@ Gun.on('create', function(root){ } if(!graph && data){ each(data, '') } } - //console.log("GOT!", id, JSON.stringify(key), ((+new Date) - start)); root.on('in', {'@': id, put: graph, err: err? err : u, rad: Radix}); }, o); function each(val, has, a,b){ diff --git a/src/put.js b/src/put.js index c4a759d4..4e23d8b4 100644 --- a/src/put.js +++ b/src/put.js @@ -127,7 +127,6 @@ function batch(){ var as = this; }, as); if(as.res){ as.res() } } function no(v,k){ if(v){ return true } } -//console.debug(999,1); var C = 0; setInterval(function(){ try{ debug.innerHTML = C }catch(e){console.log(e)} }, 500); function map(v,k,n, at){ var as = this; var is = Gun.is(v); @@ -157,7 +156,7 @@ function soul(id, as, msg, eve){ 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? if(eve){ eve.stun = true } if(!id){ // polyfill async uuid for SEA - at.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback + as.via.back('opt.uuid')(function(err, id){ // TODO: improve perf without anonymous callback if(err){ return Gun.log(err) } // TODO: Handle error. solve(at, at.dub = at.dub || id, cat, as); }); diff --git a/src/root.js b/src/root.js index dade874c..94a2f244 100644 --- a/src/root.js +++ b/src/root.js @@ -153,6 +153,7 @@ Gun.dup = require('./dup'); Gun.on.get = function(msg, gun){ var root = gun._, get = msg.get, soul = get[_soul], node = root.graph[soul], has = get[_has], tmp; var next = root.next || (root.next = {}), at = next[soul]; + // queue concurrent GETs? if(!node){ return root.on('get', msg) } if(has){ if('string' != typeof has || !obj_has(node, has)){ return root.on('get', msg) } @@ -193,6 +194,7 @@ Gun.dup = require('./dup'); at.opt.peers = at.opt.peers || {}; obj_map(opt, function each(v,k){ if(!obj_has(this, k) || text.is(v) || obj.empty(v)){ this[k] = v ; return } + if(v && v.constructor !== Object && !list_is(v)){ return } obj_map(v, each, this[k]); }, at.opt); Gun.on('opt', at); diff --git a/test/common.js b/test/common.js index 0c2de5b8..8bf55968 100644 --- a/test/common.js +++ b/test/common.js @@ -3692,7 +3692,6 @@ describe('Gun', function(){ expect(gone[index]).to.not.be.ok(); gone[index] = diff; largest = (largest < diff)? diff : largest; - //console.log(diff, '<', max); expect(diff > max).to.not.be.ok(); }); var turns = 0; diff --git a/test/rad/rad.js b/test/rad/rad.js index bd97283d..6d07686e 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -113,15 +113,22 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam it('radix reverse', function(done){ var r = Radix(), tmp; - r('alice', 1);r('bob', 2);r('carl', 3);r('dave', 4); + r('alice', 1);r('bob', 2);r('carl', 3);r('carlo',4); + r('dave', 5);r('zach',6);r('zachary',7); + var by = ['alice','bob','carl','carlo','dave','zach','zachary']; + Gun.obj.map(by, function(k,i){ + r(k,i); + }); Radix.map(r, function(v,k, a,b){ + expect(by.pop()).to.be(k); tmp = v; }, {reverse: 1}); expect(tmp).to.be(1); + expect(by.length).to.be(0); Radix.map(r, function(v,k, a,b){ tmp = v; }); - expect(tmp).to.be(4); + expect(tmp).to.be(7); done(); }); }); From ab69258633734484753e14a5bb8f8f833824018b Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 10 Sep 2019 14:45:47 -0700 Subject: [PATCH 08/19] adjust format after merge --- sea.js | 2426 +++++++++++++++++++++----------------------------------- 1 file changed, 896 insertions(+), 1530 deletions(-) diff --git a/sea.js b/sea.js index 91bbd8c3..0a931a6a 100644 --- a/sea.js +++ b/sea.js @@ -1,1007 +1,647 @@ -(function() { +;(function(){ + /* UNBUILD */ var root; - if (typeof window !== "undefined") { - root = window; - } - if (typeof global !== "undefined") { - root = global; - } + if(typeof window !== "undefined"){ root = window } + if(typeof global !== "undefined"){ root = global } root = root || {}; - var console = root.console || { log: function() {} }; - function USE(arg, req) { - return req - ? require(arg) - : arg.slice - ? USE[R(arg)] - : function(mod, path) { - arg((mod = { exports: {} })); - USE[R(path)] = mod.exports; - }; - function R(p) { - return p - .split("/") - .slice(-1) - .toString() - .replace(".js", ""); + var console = root.console || {log: function(){}}; + function USE(arg, req){ + return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){ + arg(mod = {exports: {}}); + USE[R(path)] = mod.exports; + } + function R(p){ + return p.split('/').slice(-1).toString().replace('.js',''); } } - if (typeof module !== "undefined") { - var common = module; - } + if(typeof module !== "undefined"){ var common = module } /* UNBUILD */ - USE(function(module) { + ;USE(function(module){ // Security, Encryption, and Authorization: SEA.js // MANDATORY READING: https://gun.eco/explainers/data/security.html // IT IS IMPLEMENTED IN A POLYFILL/SHIM APPROACH. // THIS IS AN EARLY ALPHA! - if (typeof window !== "undefined") { - module.window = window; - } + if(typeof window !== "undefined"){ module.window = window } var tmp = module.window || module; var SEA = tmp.SEA || {}; - if ((SEA.window = module.window)) { - SEA.window.SEA = SEA; - } + if(SEA.window = module.window){ SEA.window.SEA = SEA } - try { - if (typeof common !== "undefined") { - common.exports = SEA; - } - } catch (e) {} + try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){} module.exports = SEA; - })(USE, "./root"); + })(USE, './root'); - USE(function(module) { - var SEA = USE("./root"); - try { - if (SEA.window) { - if ( - location.protocol.indexOf("s") < 0 && - location.host.indexOf("localhost") < 0 && - location.protocol.indexOf("file:") < 0 - ) { - location.protocol = "https:"; // WebCrypto does NOT work without HTTPS! - } + ;USE(function(module){ + var SEA = USE('./root'); + try{ if(SEA.window){ + if(location.protocol.indexOf('s') < 0 + && location.host.indexOf('localhost') < 0 + && location.protocol.indexOf('file:') < 0){ + location.protocol = 'https:'; // WebCrypto does NOT work without HTTPS! } - } catch (e) {} - })(USE, "./https"); + } }catch(e){} + })(USE, './https'); - USE(function(module) { + ;USE(function(module){ // This is Array extended to have .toString(['utf8'|'hex'|'base64']) function SeaArray() {} - Object.assign(SeaArray, { from: Array.from }); - SeaArray.prototype = Object.create(Array.prototype); - SeaArray.prototype.toString = function(enc, start, end) { - enc = enc || "utf8"; - start = start || 0; - const length = this.length; - if (enc === "hex") { - const buf = new Uint8Array(this); - return [...Array(((end && end + 1) || length) - start).keys()] - .map(i => buf[i + start].toString(16).padStart(2, "0")) - .join(""); + Object.assign(SeaArray, { from: Array.from }) + SeaArray.prototype = Object.create(Array.prototype) + SeaArray.prototype.toString = function(enc, start, end) { enc = enc || 'utf8'; start = start || 0; + const length = this.length + if (enc === 'hex') { + const buf = new Uint8Array(this) + return [ ...Array(((end && (end + 1)) || length) - start).keys()] + .map((i) => buf[ i + start ].toString(16).padStart(2, '0')).join('') } - if (enc === "utf8") { - return Array.from({ length: (end || length) - start }, (_, i) => - String.fromCharCode(this[i + start]) - ).join(""); + if (enc === 'utf8') { + return Array.from( + { length: (end || length) - start }, + (_, i) => String.fromCharCode(this[ i + start]) + ).join('') } - if (enc === "base64") { - return btoa(this); + if (enc === 'base64') { + return btoa(this) } - }; + } module.exports = SeaArray; - })(USE, "./array"); + })(USE, './array'); - USE(function(module) { + ;USE(function(module){ // This is Buffer implementation used in SEA. Functionality is mostly // compatible with NodeJS 'safe-buffer' and is used for encoding conversions // between binary and 'hex' | 'utf8' | 'base64' // See documentation and validation for safe implementation in: // https://github.com/feross/safe-buffer#update - var SeaArray = USE("./array"); + var SeaArray = USE('./array'); function SafeBuffer(...props) { - console.warn( - "new SafeBuffer() is depreciated, please use SafeBuffer.from()" - ); - return SafeBuffer.from(...props); + console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()') + return SafeBuffer.from(...props) } - SafeBuffer.prototype = Object.create(Array.prototype); + SafeBuffer.prototype = Object.create(Array.prototype) Object.assign(SafeBuffer, { // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' from() { if (!Object.keys(arguments).length) { - throw new TypeError( - "First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object." - ); + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') } - const input = arguments[0]; - let buf; - if (typeof input === "string") { - const enc = arguments[1] || "utf8"; - if (enc === "hex") { - const bytes = input - .match(/([\da-fA-F]{2})/g) - .map(byte => parseInt(byte, 16)); + const input = arguments[0] + let buf + if (typeof input === 'string') { + const enc = arguments[1] || 'utf8' + if (enc === 'hex') { + const bytes = input.match(/([\da-fA-F]{2})/g) + .map((byte) => parseInt(byte, 16)) if (!bytes || !bytes.length) { - throw new TypeError("Invalid first argument for type 'hex'."); + throw new TypeError('Invalid first argument for type \'hex\'.') } - buf = SeaArray.from(bytes); - } else if (enc === "utf8") { - const length = input.length; - const words = new Uint16Array(length); - Array.from( - { length: length }, - (_, i) => (words[i] = input.charCodeAt(i)) - ); - buf = SeaArray.from(words); - } else if (enc === "base64") { - const dec = atob(input); - const length = dec.length; - const bytes = new Uint8Array(length); - Array.from( - { length: length }, - (_, i) => (bytes[i] = dec.charCodeAt(i)) - ); - buf = SeaArray.from(bytes); - } else if (enc === "binary") { - buf = SeaArray.from(input); + buf = SeaArray.from(bytes) + } else if (enc === 'utf8') { + const length = input.length + const words = new Uint16Array(length) + Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i)) + buf = SeaArray.from(words) + } else if (enc === 'base64') { + const dec = atob(input) + const length = dec.length + const bytes = new Uint8Array(length) + Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i)) + buf = SeaArray.from(bytes) + } else if (enc === 'binary') { + buf = SeaArray.from(input) } else { - console.info("SafeBuffer.from unknown encoding: " + enc); + console.info('SafeBuffer.from unknown encoding: '+enc) } - return buf; + return buf } - const byteLength = input.byteLength; // what is going on here? FOR MARTTI - const length = input.byteLength ? input.byteLength : input.length; + const byteLength = input.byteLength // what is going on here? FOR MARTTI + const length = input.byteLength ? input.byteLength : input.length if (length) { - let buf; + let buf if (input instanceof ArrayBuffer) { - buf = new Uint8Array(input); + buf = new Uint8Array(input) } - return SeaArray.from(buf || input); + return SeaArray.from(buf || input) } }, // This is 'safe-buffer.alloc' sans encoding support - alloc(length, fill = 0 /*, enc*/) { - return SeaArray.from( - new Uint8Array(Array.from({ length: length }, () => fill)) - ); + alloc(length, fill = 0 /*, enc*/ ) { + return SeaArray.from(new Uint8Array(Array.from({ length: length }, () => fill))) }, // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! allocUnsafe(length) { - return SeaArray.from(new Uint8Array(Array.from({ length: length }))); + return SeaArray.from(new Uint8Array(Array.from({ length : length }))) }, // This puts together array of array like members - concat(arr) { - // octet array + concat(arr) { // octet array if (!Array.isArray(arr)) { - throw new TypeError( - "First argument must be Array containing ArrayBuffer or Uint8Array instances." - ); + throw new TypeError('First argument must be Array containing ArrayBuffer or Uint8Array instances.') } - return SeaArray.from( - arr.reduce((ret, item) => ret.concat(Array.from(item)), []) - ); + return SeaArray.from(arr.reduce((ret, item) => ret.concat(Array.from(item)), [])) } - }); - SafeBuffer.prototype.from = SafeBuffer.from; - SafeBuffer.prototype.toString = SeaArray.prototype.toString; + }) + SafeBuffer.prototype.from = SafeBuffer.from + SafeBuffer.prototype.toString = SeaArray.prototype.toString module.exports = SafeBuffer; - })(USE, "./buffer"); + })(USE, './buffer'); - USE(function(module) { - const SEA = USE("./root"); - const Buffer = USE("./buffer"); - const api = { Buffer: Buffer }; + ;USE(function(module){ + const SEA = USE('./root') + const Buffer = USE('./buffer') + const api = {Buffer: Buffer} var o = {}; - if (SEA.window) { + if(SEA.window){ api.crypto = window.crypto || window.msCrypto; - api.subtle = (api.crypto || o).subtle || (api.crypto || o).webkitSubtle; + api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle; api.TextEncoder = window.TextEncoder; api.TextDecoder = window.TextDecoder; - api.random = len => - Buffer.from( - api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len))) - ); + api.random = (len) => Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) } - if (!api.crypto) { - try { - var crypto = USE("crypto", 1); - const { TextEncoder, TextDecoder } = USE("text-encoding", 1); - Object.assign(api, { - crypto, - //subtle, - TextEncoder, - TextDecoder, - random: len => Buffer.from(crypto.randomBytes(len)) - }); - //try{ - const WebCrypto = USE("node-webcrypto-ossl", 1); - api.ossl = api.subtle = new WebCrypto({ directory: "ossl" }).subtle; // ECDH - //}catch(e){ + if(!api.crypto){try{ + var crypto = USE('crypto', 1); + const { TextEncoder, TextDecoder } = USE('text-encoding', 1) + Object.assign(api, { + crypto, + //subtle, + TextEncoder, + TextDecoder, + random: (len) => Buffer.from(crypto.randomBytes(len)) + }); + //try{ + const WebCrypto = USE('node-webcrypto-ossl', 1); + api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH + //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); - //} - } catch (e) { - console.log( - "node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!" - ); - OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; - } - } + //} + }catch(e){ + console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!"); + OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; + }} - module.exports = api; - })(USE, "./shim"); + module.exports = api + })(USE, './shim'); - USE(function(module) { - var SEA = USE("./root"); - var Buffer = USE("./buffer"); + ;USE(function(module){ + var SEA = USE('./root'); + var Buffer = USE('./buffer'); var s = {}; - s.pbkdf2 = { hash: "SHA-256", iter: 100000, ks: 64 }; + s.pbkdf2 = {hash: 'SHA-256', iter: 100000, ks: 64}; s.ecdsa = { - pair: { name: "ECDSA", namedCurve: "P-256" }, - sign: { name: "ECDSA", hash: { name: "SHA-256" } } + pair: {name: 'ECDSA', namedCurve: 'P-256'}, + sign: {name: 'ECDSA', hash: {name: 'SHA-256'}} }; - s.ecdh = { name: "ECDH", namedCurve: "P-256" }; + s.ecdh = {name: 'ECDH', namedCurve: 'P-256'}; // This creates Web Cryptography API compliant JWK for sign/verify purposes - s.jwk = function(pub, d) { - // d === priv - pub = pub.split("."); - var x = pub[0], - y = pub[1]; - var jwk = { kty: "EC", crv: "P-256", x: x, y: y, ext: true }; - jwk.key_ops = d ? ["sign"] : ["verify"]; - if (d) { - jwk.d = d; - } + s.jwk = function(pub, d){ // d === priv + pub = pub.split('.'); + var x = pub[0], y = pub[1]; + var jwk = {kty: "EC", crv: "P-256", x: x, y: y, ext: true}; + jwk.key_ops = d ? ['sign'] : ['verify']; + if(d){ jwk.d = d } return jwk; }; s.recall = { validity: 12 * 60 * 60, // internally in seconds : 12 hours - hook: function(props) { - return props; - } // { iat, exp, alias, remember } // or return new Promise((resolve, reject) => resolve(props) + hook: function(props){ return props } // { iat, exp, alias, remember } // or return new Promise((resolve, reject) => resolve(props) }; - s.check = function(t) { - return typeof t == "string" && "SEA{" === t.slice(0, 4); - }; - s.parse = function p(t) { - try { - var yes = typeof t == "string"; - if (yes && "SEA{" === t.slice(0, 4)) { - t = t.slice(3); - } - return yes ? JSON.parse(t) : t; + s.check = function(t){ return (typeof t == 'string') && ('SEA{' === t.slice(0,4)) } + s.parse = function p(t){ try { + var yes = (typeof t == 'string'); + if(yes && 'SEA{' === t.slice(0,4)){ t = t.slice(3) } + return yes ? JSON.parse(t) : t; } catch (e) {} return t; - }; + } SEA.opt = s; - module.exports = s; - })(USE, "./settings"); + module.exports = s + })(USE, './settings'); - USE(function(module) { - var shim = USE("./shim"); - module.exports = async function(d, o) { - var t = typeof d == "string" ? d : JSON.stringify(d); - var hash = await shim.subtle.digest( - { name: o || "SHA-256" }, - new shim.TextEncoder().encode(t) - ); + ;USE(function(module){ + var shim = USE('./shim'); + module.exports = async function(d, o){ + var t = (typeof d == 'string')? d : JSON.stringify(d); + var hash = await shim.subtle.digest({name: o||'SHA-256'}, new shim.TextEncoder().encode(t)); return shim.Buffer.from(hash); - }; - })(USE, "./sha256"); + } + })(USE, './sha256'); - USE(function(module) { + ;USE(function(module){ // This internal func returns SHA-1 hashed data for KeyID generation - const __shim = USE("./shim"); - const subtle = __shim.subtle; - const ossl = __shim.ossl ? __shim.ossl : subtle; - const sha1hash = b => ossl.digest({ name: "SHA-1" }, new ArrayBuffer(b)); - module.exports = sha1hash; - })(USE, "./sha1"); + const __shim = USE('./shim') + const subtle = __shim.subtle + const ossl = __shim.ossl ? __shim.ossl : subtle + const sha1hash = (b) => ossl.digest({name: 'SHA-1'}, new ArrayBuffer(b)) + module.exports = sha1hash + })(USE, './sha1'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - var sha = USE("./sha256"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + var sha = USE('./sha256'); var u; - SEA.work = - SEA.work || - (async (data, pair, cb, opt) => { - try { - // used to be named `proof` - var salt = (pair || {}).epub || pair; // epub not recommended, salt should be random! - var opt = opt || {}; - if (salt instanceof Function) { - cb = salt; - salt = u; - } - salt = salt || shim.random(9); - data = typeof data == "string" ? data : JSON.stringify(data); - if ("sha" === (opt.name || "").toLowerCase().slice(0, 3)) { - var rsha = shim.Buffer.from( - await sha(data, opt.name), - "binary" - ).toString(opt.encode || "base64"); - if (cb) { - try { - cb(rsha); - } catch (e) { - console.log(e); - } - } - return rsha; - } - var key = await (shim.ossl || shim.subtle).importKey( - "raw", - new shim.TextEncoder().encode(data), - { name: opt.name || "PBKDF2" }, - false, - ["deriveBits"] - ); - var work = await (shim.ossl || shim.subtle).deriveBits( - { - name: opt.name || "PBKDF2", - iterations: opt.iterations || S.pbkdf2.iter, - salt: new shim.TextEncoder().encode(opt.salt || salt), - hash: opt.hash || S.pbkdf2.hash - }, - key, - opt.length || S.pbkdf2.ks * 8 - ); - data = shim.random(data.length); // Erase data in case of passphrase - var r = shim.Buffer.from(work, "binary").toString( - opt.encode || "base64" - ); - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + SEA.work = SEA.work || (async (data, pair, cb, opt) => { try { // used to be named `proof` + var salt = (pair||{}).epub || pair; // epub not recommended, salt should be random! + var opt = opt || {}; + if(salt instanceof Function){ + cb = salt; + salt = u; + } + salt = salt || shim.random(9); + data = (typeof data == 'string')? data : JSON.stringify(data); + if('sha' === (opt.name||'').toLowerCase().slice(0,3)){ + var rsha = shim.Buffer.from(await sha(data, opt.name), 'binary').toString(opt.encode || 'base64') + if(cb){ try{ cb(rsha) }catch(e){console.log(e)} } + return rsha; + } + var key = await (shim.ossl || shim.subtle).importKey('raw', new shim.TextEncoder().encode(data), {name: opt.name || 'PBKDF2'}, false, ['deriveBits']); + var work = await (shim.ossl || shim.subtle).deriveBits({ + name: opt.name || 'PBKDF2', + iterations: opt.iterations || S.pbkdf2.iter, + salt: new shim.TextEncoder().encode(opt.salt || salt), + hash: opt.hash || S.pbkdf2.hash, + }, key, opt.length || (S.pbkdf2.ks * 8)) + data = shim.random(data.length) // Erase data in case of passphrase + var r = shim.Buffer.from(work, 'binary').toString(opt.encode || 'base64') + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.work; - })(USE, "./work"); + })(USE, './work'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); - SEA.name = - SEA.name || - (async (cb, opt) => { - try { - if (cb) { - try { - cb(); - } catch (e) { - console.log(e); - } - } - return; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + SEA.name = SEA.name || (async (cb, opt) => { try { + if(cb){ try{ cb() }catch(e){console.log(e)} } + return; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); //SEA.pair = async (data, proof, cb) => { try { - SEA.pair = - SEA.pair || - (async (cb, opt) => { - try { - var ecdhSubtle = shim.ossl || shim.subtle; - // First: ECDSA keys for signing/verifying... - var sa = await shim.subtle - .generateKey(S.ecdsa.pair, true, ["sign", "verify"]) - .then(async keys => { - // privateKey scope doesn't leak out from here! - //const { d: priv } = await shim.subtle.exportKey('jwk', keys.privateKey) - var key = {}; - key.priv = (await shim.subtle.exportKey( - "jwk", - keys.privateKey - )).d; - var pub = await shim.subtle.exportKey("jwk", keys.publicKey); - //const pub = Buff.from([ x, y ].join(':')).toString('base64') // old - key.pub = pub.x + "." + pub.y; // new - // x and y are already base64 - // pub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) - // but split on a non-base64 letter. - return key; - }); + SEA.pair = SEA.pair || (async (cb, opt) => { try { - // To include PGPv4 kind of keyId: - // const pubId = await SEA.keyid(keys.pub) - // Next: ECDH keys for encryption/decryption... + var ecdhSubtle = shim.ossl || shim.subtle; + // First: ECDSA keys for signing/verifying... + var sa = await shim.subtle.generateKey(S.ecdsa.pair, true, [ 'sign', 'verify' ]) + .then(async (keys) => { + // privateKey scope doesn't leak out from here! + //const { d: priv } = await shim.subtle.exportKey('jwk', keys.privateKey) + var key = {}; + key.priv = (await shim.subtle.exportKey('jwk', keys.privateKey)).d; + var pub = await shim.subtle.exportKey('jwk', keys.publicKey); + //const pub = Buff.from([ x, y ].join(':')).toString('base64') // old + key.pub = pub.x+'.'+pub.y; // new + // x and y are already base64 + // pub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) + // but split on a non-base64 letter. + return key; + }) + + // To include PGPv4 kind of keyId: + // const pubId = await SEA.keyid(keys.pub) + // Next: ECDH keys for encryption/decryption... - try { - var dh = await ecdhSubtle - .generateKey(S.ecdh, true, ["deriveKey"]) - .then(async keys => { - // privateKey scope doesn't leak out from here! - var key = {}; - key.epriv = (await ecdhSubtle.exportKey( - "jwk", - keys.privateKey - )).d; - var pub = await ecdhSubtle.exportKey("jwk", keys.publicKey); - //const epub = Buff.from([ ex, ey ].join(':')).toString('base64') // old - key.epub = pub.x + "." + pub.y; // new - // ex and ey are already base64 - // epub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) - // but split on a non-base64 letter. - return key; - }); - } catch (e) { - if (SEA.window) { - throw e; - } - if (e == "Error: ECDH is not a supported algorithm") { - console.log("Ignoring ECDH..."); - } else { - throw e; - } - } - dh = dh || {}; + try{ + var dh = await ecdhSubtle.generateKey(S.ecdh, true, ['deriveKey']) + .then(async (keys) => { + // privateKey scope doesn't leak out from here! + var key = {}; + key.epriv = (await ecdhSubtle.exportKey('jwk', keys.privateKey)).d; + var pub = await ecdhSubtle.exportKey('jwk', keys.publicKey); + //const epub = Buff.from([ ex, ey ].join(':')).toString('base64') // old + key.epub = pub.x+'.'+pub.y; // new + // ex and ey are already base64 + // epub is UTF8 but filename/URL safe (https://www.ietf.org/rfc/rfc3986.txt) + // but split on a non-base64 letter. + return key; + }) + }catch(e){ + if(SEA.window){ throw e } + if(e == 'Error: ECDH is not a supported algorithm'){ console.log('Ignoring ECDH...') } + else { throw e } + } dh = dh || {}; - var r = { - pub: sa.pub, - priv: sa.priv, - /* pubId, */ epub: dh.epub, - epriv: dh.epriv - }; - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + var r = { pub: sa.pub, priv: sa.priv, /* pubId, */ epub: dh.epub, epriv: dh.epriv } + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.pair; - })(USE, "./pair"); + })(USE, './pair'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - var sha = USE("./sha256"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + var sha = USE('./sha256'); var u; - SEA.sign = - SEA.sign || - (async (data, pair, cb, opt) => { - try { - opt = opt || {}; - if (!(pair || opt).priv) { - pair = await SEA.I(null, { what: data, how: "sign", why: opt.why }); - } - if (u === data) { - throw "`undefined` not allowed."; - } - var json = S.parse(data); - var check = (opt.check = opt.check || json); - if ( - SEA.verify && - (SEA.opt.check(check) || (check && check.s && check.m)) && - u !== (await SEA.verify(check, pair)) - ) { - // don't sign if we already signed it. - var r = S.parse(check); - if (!opt.raw) { - r = "SEA" + JSON.stringify(r); - } - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } - var pub = pair.pub; - var priv = pair.priv; - var jwk = S.jwk(pub, priv); - var hash = await sha(json); - var sig = await (shim.ossl || shim.subtle) - .importKey("jwk", jwk, S.ecdsa.pair, false, ["sign"]) - .then(key => - (shim.ossl || shim.subtle).sign( - S.ecdsa.sign, - key, - new Uint8Array(hash) - ) - ); // privateKey scope doesn't leak out from here! - var r = { - m: json, - s: shim.Buffer.from(sig, "binary").toString(opt.encode || "base64") - }; - if (!opt.raw) { - r = "SEA" + JSON.stringify(r); - } + SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try { + opt = opt || {}; + if(!(pair||opt).priv){ + pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why}); + } + if(u === data){ throw '`undefined` not allowed.' } + var json = S.parse(data); + var check = opt.check = opt.check || json; + if(SEA.verify && (SEA.opt.check(check) || (check && check.s && check.m)) + && u !== await SEA.verify(check, pair)){ // don't sign if we already signed it. + var r = S.parse(check); + if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } + var pub = pair.pub; + var priv = pair.priv; + var jwk = S.jwk(pub, priv); + var hash = await sha(json); + var sig = await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['sign']) + .then((key) => (shim.ossl || shim.subtle).sign(S.ecdsa.sign, key, new Uint8Array(hash))) // privateKey scope doesn't leak out from here! + var r = {m: json, s: shim.Buffer.from(sig, 'binary').toString(opt.encode || 'base64')} + if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.sign; - })(USE, "./sign"); + })(USE, './sign'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - var sha = USE("./sha256"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + var sha = USE('./sha256'); var u; - SEA.verify = - SEA.verify || - (async (data, pair, cb, opt) => { - try { - var json = S.parse(data); - if (false === pair) { - // don't verify! - var raw = S.parse(json.m); - if (cb) { - try { - cb(raw); - } catch (e) { - console.log(e); - } - } - return raw; - } - opt = opt || {}; - // SEA.I // verify is free! Requires no user permission. - var pub = pair.pub || pair; - var key = SEA.opt.slow_leak - ? await SEA.opt.slow_leak(pub) - : await (shim.ossl || shim.subtle).importKey( - "jwk", - jwk, - S.ecdsa.pair, - false, - ["verify"] - ); - var hash = await sha(json.m); - var buf, sig, check, tmp; - try { - buf = shim.Buffer.from(json.s, opt.encode || "base64"); // NEW DEFAULT! - sig = new Uint8Array(buf); - check = await (shim.ossl || shim.subtle).verify( - S.ecdsa.sign, - key, - sig, - new Uint8Array(hash) - ); - if (!check) { - throw "Signature did not match."; - } - } catch (e) { - if (SEA.opt.fallback) { - return await SEA.opt.fall_verify(data, pair, cb, opt); - } - } - var r = check ? S.parse(json.m) : u; - - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); // mismatched owner FOR MARTTI - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; + SEA.verify = SEA.verify || (async (data, pair, cb, opt) => { try { + var json = S.parse(data); + if(false === pair){ // don't verify! + var raw = S.parse(json.m); + if(cb){ try{ cb(raw) }catch(e){console.log(e)} } + return raw; + } + opt = opt || {}; + // SEA.I // verify is free! Requires no user permission. + var pub = pair.pub || pair; + var key = SEA.opt.slow_leak? await SEA.opt.slow_leak(pub) : await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['verify']); + var hash = await sha(json.m); + var buf, sig, check, tmp; try{ + buf = shim.Buffer.from(json.s, opt.encode || 'base64'); // NEW DEFAULT! + sig = new Uint8Array(buf); + check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)); + if(!check){ throw "Signature did not match." } + }catch(e){ + if(SEA.opt.fallback){ + return await SEA.opt.fall_verify(data, pair, cb, opt); } - }); + } + var r = check? S.parse(json.m) : u; + + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); // mismatched owner FOR MARTTI + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.verify; // legacy & ossl leak mitigation: var knownKeys = {}; - var keyForPair = (SEA.opt.slow_leak = pair => { + var keyForPair = SEA.opt.slow_leak = pair => { if (knownKeys[pair]) return knownKeys[pair]; var jwk = S.jwk(pair); - knownKeys[pair] = (shim.ossl || shim.subtle).importKey( - "jwk", - jwk, - S.ecdsa.pair, - false, - ["verify"] - ); + knownKeys[pair] = (shim.ossl || shim.subtle).importKey("jwk", jwk, S.ecdsa.pair, false, ["verify"]); return knownKeys[pair]; - }); - - SEA.opt.fall_verify = async function(data, pair, cb, opt, f) { - if (f === SEA.opt.fallback) { - throw "Signature did not match"; - } - f = f || 1; - var json = S.parse(data), - pub = pair.pub || pair, - key = await SEA.opt.slow_leak(pub); - var hash = - f <= SEA.opt.fallback - ? shim.Buffer.from( - await shim.subtle.digest( - { name: "SHA-256" }, - new shim.TextEncoder().encode(S.parse(json.m)) - ) - ) - : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. - var buf; - var sig; - var check; - try { - buf = shim.Buffer.from(json.s, opt.encode || "base64"); // NEW DEFAULT! - sig = new Uint8Array(buf); - check = await (shim.ossl || shim.subtle).verify( - S.ecdsa.sign, - key, - sig, - new Uint8Array(hash) - ); - if (!check) { - throw "Signature did not match."; - } - } catch (e) { - buf = shim.Buffer.from(json.s, "utf8"); // AUTO BACKWARD OLD UTF8 DATA! - sig = new Uint8Array(buf); - check = await (shim.ossl || shim.subtle).verify( - S.ecdsa.sign, - key, - sig, - new Uint8Array(hash) - ); - if (!check) { - throw "Signature did not match."; - } - } - var r = check ? S.parse(json.m) : u; - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; }; - SEA.opt.fallback = 2; - })(USE, "./verify"); - USE(function(module) { - var shim = USE("./shim"); - var sha256hash = USE("./sha256"); + + SEA.opt.fall_verify = async function(data, pair, cb, opt, f){ + if(f === SEA.opt.fallback){ throw "Signature did not match" } f = f || 1; + var json = S.parse(data), pub = pair.pub || pair, key = await SEA.opt.slow_leak(pub); + var hash = (f <= SEA.opt.fallback)? shim.Buffer.from(await shim.subtle.digest({name: 'SHA-256'}, new shim.TextEncoder().encode(S.parse(json.m)))) : await sha(json.m); // this line is old bad buggy code but necessary for old compatibility. + var buf; var sig; var check; try{ + buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT! + sig = new Uint8Array(buf) + check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)) + if(!check){ throw "Signature did not match." } + }catch(e){ + buf = shim.Buffer.from(json.s, 'utf8') // AUTO BACKWARD OLD UTF8 DATA! + sig = new Uint8Array(buf) + check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash)) + if(!check){ throw "Signature did not match." } + } + var r = check? S.parse(json.m) : u; + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } + SEA.opt.fallback = 2; + + })(USE, './verify'); + + ;USE(function(module){ + var shim = USE('./shim'); + var sha256hash = USE('./sha256'); const importGen = async (key, salt, opt) => { //const combo = shim.Buffer.concat([shim.Buffer.from(key, 'utf8'), salt || shim.random(8)]).toString('utf8') // old var opt = opt || {}; - const combo = key + (salt || shim.random(8)).toString("utf8"); // new - const hash = shim.Buffer.from(await sha256hash(combo), "binary"); - return await shim.subtle.importKey( - "raw", - new Uint8Array(hash), - opt.name || "AES-GCM", - false, - ["encrypt", "decrypt"] - ); - }; + const combo = key + (salt || shim.random(8)).toString('utf8'); // new + const hash = shim.Buffer.from(await sha256hash(combo), 'binary') + return await shim.subtle.importKey('raw', new Uint8Array(hash), opt.name || 'AES-GCM', false, ['encrypt', 'decrypt']) + } module.exports = importGen; - })(USE, "./aeskey"); + })(USE, './aeskey'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - var aeskey = USE("./aeskey"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + var aeskey = USE('./aeskey'); var u; - SEA.encrypt = - SEA.encrypt || - (async (data, pair, cb, opt) => { - try { - opt = opt || {}; - var key = (pair || opt).epriv || pair; - if (u === data) { - throw "`undefined` not allowed."; - } - if (!key) { - pair = await SEA.I(null, { - what: data, - how: "encrypt", - why: opt.why - }); - key = pair.epriv || pair; - } - var msg = typeof data == "string" ? data : JSON.stringify(data); - var rand = { s: shim.random(9), iv: shim.random(15) }; // consider making this 9 and 15 or 18 or 12 to reduce == padding. - var ct = await aeskey(key, rand.s, opt).then(aes => - shim /*shim.ossl ||*/.subtle - .encrypt( - { - // Keeping the AES key scope as private as possible... - name: opt.name || "AES-GCM", - iv: new Uint8Array(rand.iv) - }, - aes, - new shim.TextEncoder().encode(msg) - ) - ); - var r = { - ct: shim.Buffer.from(ct, "binary").toString(opt.encode || "base64"), - iv: rand.iv.toString(opt.encode || "base64"), - s: rand.s.toString(opt.encode || "base64") - }; - if (!opt.raw) { - r = "SEA" + JSON.stringify(r); - } + SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try { + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(u === data){ throw '`undefined` not allowed.' } + if(!key){ + pair = await SEA.I(null, {what: data, how: 'encrypt', why: opt.why}); + key = pair.epriv || pair; + } + var msg = (typeof data == 'string')? data : JSON.stringify(data); + var rand = {s: shim.random(9), iv: shim.random(15)}; // consider making this 9 and 15 or 18 or 12 to reduce == padding. + var ct = await aeskey(key, rand.s, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).encrypt({ // Keeping the AES key scope as private as possible... + name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv) + }, aes, new shim.TextEncoder().encode(msg))); + var r = { + ct: shim.Buffer.from(ct, 'binary').toString(opt.encode || 'base64'), + iv: rand.iv.toString(opt.encode || 'base64'), + s: rand.s.toString(opt.encode || 'base64') + } + if(!opt.raw){ r = 'SEA'+JSON.stringify(r) } - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.encrypt; - })(USE, "./encrypt"); + })(USE, './encrypt'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - var aeskey = USE("./aeskey"); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + var aeskey = USE('./aeskey'); - SEA.decrypt = - SEA.decrypt || - (async (data, pair, cb, opt) => { - try { - opt = opt || {}; - var key = (pair || opt).epriv || pair; - if (!key) { - pair = await SEA.I(null, { - what: data, - how: "decrypt", - why: opt.why - }); - key = pair.epriv || pair; - } - var json = S.parse(data); - var buf, bufiv, bufct; - try { - buf = shim.Buffer.from(json.s, opt.encode || "base64"); - bufiv = shim.Buffer.from(json.iv, opt.encode || "base64"); - bufct = shim.Buffer.from(json.ct, opt.encode || "base64"); - var ct = await aeskey(key, buf, opt).then(aes => - shim /*shim.ossl ||*/.subtle - .decrypt( - { - // Keeping aesKey scope as private as possible... - name: opt.name || "AES-GCM", - iv: new Uint8Array(bufiv) - }, - aes, - new Uint8Array(bufct) - ) - ); - } catch (e) { - if ("utf8" === opt.encode) { - throw "Could not decrypt"; - } - if (SEA.opt.fallback) { - opt.encode = "utf8"; - return await SEA.decrypt(data, pair, cb, opt); - } - } - var r = S.parse(new shim.TextDecoder("utf8").decode(ct)); - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; + SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try { + opt = opt || {}; + var key = (pair||opt).epriv || pair; + if(!key){ + pair = await SEA.I(null, {what: data, how: 'decrypt', why: opt.why}); + key = pair.epriv || pair; + } + var json = S.parse(data); + var buf, bufiv, bufct; try{ + buf = shim.Buffer.from(json.s, opt.encode || 'base64'); + bufiv = shim.Buffer.from(json.iv, opt.encode || 'base64'); + bufct = shim.Buffer.from(json.ct, opt.encode || 'base64'); + var ct = await aeskey(key, buf, opt).then((aes) => (/*shim.ossl ||*/ shim.subtle).decrypt({ // Keeping aesKey scope as private as possible... + name: opt.name || 'AES-GCM', iv: new Uint8Array(bufiv) + }, aes, new Uint8Array(bufct))); + }catch(e){ + if('utf8' === opt.encode){ throw "Could not decrypt" } + if(SEA.opt.fallback){ + opt.encode = 'utf8'; + return await SEA.decrypt(data, pair, cb, opt); } - }); + } + var r = S.parse(new shim.TextDecoder('utf8').decode(ct)); + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); module.exports = SEA.decrypt; - })(USE, "./decrypt"); + })(USE, './decrypt'); - USE(function(module) { - var SEA = USE("./root"); - var shim = USE("./shim"); - var S = USE("./settings"); - // Derive shared secret from other's pub and my epub/epriv - SEA.secret = - SEA.secret || - (async (key, pair, cb, opt) => { - try { - opt = opt || {}; - if (!pair || !pair.epriv || !pair.epub) { - pair = await SEA.I(null, { - what: key, - how: "secret", - why: opt.why - }); - } - var pub = key.epub || key; - var epub = pair.epub; - var epriv = pair.epriv; - var ecdhSubtle = shim.ossl || shim.subtle; - var pubKeyData = keysToEcdhJwk(pub); - var props = Object.assign( - { public: await ecdhSubtle.importKey(...pubKeyData, true, []) }, - S.ecdh - ); - var privKeyData = keysToEcdhJwk(epub, epriv); - var derived = await ecdhSubtle - .importKey(...privKeyData, false, ["deriveKey"]) - .then(async privKey => { - // privateKey scope doesn't leak out from here! - var derivedKey = await ecdhSubtle.deriveKey( - props, - privKey, - { name: "AES-GCM", length: 256 }, - true, - ["encrypt", "decrypt"] - ); - return ecdhSubtle.exportKey("jwk", derivedKey).then(({ k }) => k); - }); - var r = derived; - if (cb) { - try { - cb(r); - } catch (e) { - console.log(e); - } - } - return r; - } catch (e) { - console.log(e); - SEA.err = e; - if (SEA.throw) { - throw e; - } - if (cb) { - cb(); - } - return; - } - }); + ;USE(function(module){ + var SEA = USE('./root'); + var shim = USE('./shim'); + var S = USE('./settings'); + // Derive shared secret from other's pub and my epub/epriv + SEA.secret = SEA.secret || (async (key, pair, cb, opt) => { try { + opt = opt || {}; + if(!pair || !pair.epriv || !pair.epub){ + pair = await SEA.I(null, {what: key, how: 'secret', why: opt.why}); + } + var pub = key.epub || key; + var epub = pair.epub; + var epriv = pair.epriv; + var ecdhSubtle = shim.ossl || shim.subtle; + var pubKeyData = keysToEcdhJwk(pub); + var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },S.ecdh); // Thanks to @sirpy ! + var privKeyData = keysToEcdhJwk(epub, epriv); + var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']).then(async (privKey) => { + // privateKey scope doesn't leak out from here! + var derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-GCM', length: 256 }, true, [ 'encrypt', 'decrypt' ]); + return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k); + }) + var r = derived; + if(cb){ try{ cb(r) }catch(e){console.log(e)} } + return r; + } catch(e) { + console.log(e); + SEA.err = e; + if(SEA.throw){ throw e } + if(cb){ cb() } + return; + }}); // can this be replaced with settings.jwk? - var keysToEcdhJwk = (pub, d) => { - // d === priv + var keysToEcdhJwk = (pub, d) => { // d === priv //var [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old - var [x, y] = pub.split("."); // new - var jwk = d ? { d: d } : {}; - return [ - // Use with spread returned value... - "jwk", - Object.assign(jwk, { x: x, y: y, kty: "EC", crv: "P-256", ext: true }), // ??? refactor + var [ x, y ] = pub.split('.') // new + var jwk = d ? { d: d } : {} + return [ // Use with spread returned value... + 'jwk', + Object.assign( + jwk, + { x: x, y: y, kty: 'EC', crv: 'P-256', ext: true } + ), // ??? refactor S.ecdh - ]; - }; + ] + } module.exports = SEA.secret; - })(USE, "./secret"); + })(USE, './secret'); - USE(function(module) { - var shim = USE("./shim"); + ;USE(function(module){ + var shim = USE('./shim'); // Practical examples about usage found from ./test/common.js - var SEA = USE("./root"); - SEA.work = USE("./work"); - SEA.sign = USE("./sign"); - SEA.verify = USE("./verify"); - SEA.encrypt = USE("./encrypt"); - SEA.decrypt = USE("./decrypt"); + var SEA = USE('./root'); + SEA.work = USE('./work'); + SEA.sign = USE('./sign'); + SEA.verify = USE('./verify'); + SEA.encrypt = USE('./encrypt'); + SEA.decrypt = USE('./decrypt'); SEA.random = SEA.random || shim.random; // This is Buffer used in SEA and usable from Gun/SEA application also. // For documentation see https://nodejs.org/api/buffer.html - SEA.Buffer = SEA.Buffer || USE("./buffer"); + SEA.Buffer = SEA.Buffer || USE('./buffer'); // These SEA functions support now ony Promises or // async/await (compatible) code, use those like Promises. @@ -1009,31 +649,25 @@ // Creates a wrapper library around Web Crypto API // for various AES, ECDSA, PBKDF2 functions we called above. // Calculate public key KeyID aka PGPv4 (result: 8 bytes as hex string) - SEA.keyid = - SEA.keyid || - (async pub => { - try { - // base64('base64(x):base64(y)') => Buffer(xy) - const pb = Buffer.concat( - pub - .replace(/-/g, "+") - .replace(/_/g, "/") - .split(".") - .map(t => Buffer.from(t, "base64")) - ); - // id is PGPv4 compliant raw key - const id = Buffer.concat([ - Buffer.from([0x99, pb.length / 0x100, pb.length % 0x100]), - pb - ]); - const sha1 = await sha1hash(id); - const hash = Buffer.from(sha1, "binary"); - return hash.toString("hex", hash.length - 8); // 16-bit ID as hex - } catch (e) { - console.log(e); - throw e; - } - }); + SEA.keyid = SEA.keyid || (async (pub) => { + try { + // base64('base64(x):base64(y)') => Buffer(xy) + const pb = Buffer.concat( + pub.replace(/-/g, '+').replace(/_/g, '/').split('.') + .map((t) => Buffer.from(t, 'base64')) + ) + // id is PGPv4 compliant raw key + const id = Buffer.concat([ + Buffer.from([0x99, pb.length / 0x100, pb.length % 0x100]), pb + ]) + const sha1 = await sha1hash(id) + const hash = Buffer.from(sha1, 'binary') + return hash.toString('hex', hash.length - 8) // 16-bit ID as hex + } catch (e) { + console.log(e) + throw e + } + }); // all done! // Obviously it is missing MANY necessary features. This is only an alpha release. // Please experiment with it, audit what I've done so far, and complain about what needs to be added. @@ -1043,108 +677,82 @@ // But all other behavior needs to be equally easy, like opinionated ways of // Adding friends (trusted public keys), sending private messages, etc. // Cheers! Tell me what you think. - var Gun = - (SEA.window || {}).Gun || - USE((typeof common == "undefined" ? "." : "") + "./gun", 1); + var Gun = (SEA.window||{}).Gun || USE((typeof common == "undefined"?'.':'')+'./gun', 1); Gun.SEA = SEA; SEA.GUN = SEA.Gun = Gun; - module.exports = SEA; - })(USE, "./sea"); + module.exports = SEA + })(USE, './sea'); - USE(function(module) { - var Gun = USE("./sea").Gun; - Gun.chain.then = function(cb) { - var gun = this, - p = new Promise(function(res, rej) { - gun.once(res); - }); - return cb ? p.then(cb) : p; - }; - })(USE, "./then"); - - USE(function(module) { - var SEA = USE("./sea"); - var Gun = SEA.Gun; - var then = USE("./then"); - - function User(root) { - this._ = { $: this }; + ;USE(function(module){ + var Gun = USE('./sea').Gun; + Gun.chain.then = function(cb){ + var gun = this, p = (new Promise(function(res, rej){ + gun.once(res); + })); + return cb? p.then(cb) : p; } - User.prototype = (function() { - function F() {} - F.prototype = Gun.chain; - return new F(); - })(); // Object.create polyfill + })(USE, './then'); + + ;USE(function(module){ + var SEA = USE('./sea'); + var Gun = SEA.Gun; + var then = USE('./then'); + + function User(root){ + this._ = {$: this}; + } + User.prototype = (function(){ function F(){}; F.prototype = Gun.chain; return new F() }()) // Object.create polyfill User.prototype.constructor = User; // let's extend the gun chain with a `user` function. // only one user can be logged in at a time, per gun instance. - Gun.chain.user = function(pub) { - var gun = this, - root = gun.back(-1), - user; - if (pub) { - return root.get("~" + pub); - } - if ((user = root.back("user"))) { - return user; - } - var root = root._, - at = root, - uuid = at.opt.uuid || Gun.state.lex; - (at = (user = at.user = gun.chain(new User()))._).opt = {}; - at.opt.uuid = function(cb) { - var id = uuid(), - pub = root.user; - if (!pub || !(pub = pub.is) || !(pub = pub.pub)) { - return id; - } - id = id + "~" + pub + "."; - if (cb && cb.call) { - cb(null, id); - } + Gun.chain.user = function(pub){ + var gun = this, root = gun.back(-1), user; + if(pub){ return root.get('~'+pub) } + if(user = root.back('user')){ return user } + var root = (root._), at = root, uuid = at.opt.uuid || Gun.state.lex; + (at = (user = at.user = gun.chain(new User))._).opt = {}; + at.opt.uuid = function(cb){ + var id = uuid(), pub = root.user; + if(!pub || !(pub = pub.is) || !(pub = pub.pub)){ return id } + id = id + '~' + pub + '.'; + if(cb && cb.call){ cb(null, id) } return id; - }; + } return user; - }; + } Gun.User = User; module.exports = User; - })(USE, "./user"); + })(USE, './user'); - USE(function(module) { + ;USE(function(module){ // TODO: This needs to be split into all separate functions. // Not just everything thrown into 'create'. - var SEA = USE("./sea"); - var User = USE("./user"); - var authsettings = USE("./settings"); + var SEA = USE('./sea'); + var User = USE('./user'); + var authsettings = USE('./settings'); var Gun = SEA.Gun; - var noop = function() {}; + var noop = function(){}; // Well first we have to actually create a user. That is what this function does. - User.prototype.create = function(alias, pass, cb, opt) { - var gun = this, - cat = gun._, - root = gun.back(-1); + User.prototype.create = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); cb = cb || noop; - if (cat.ing) { - cb({ - err: Gun.log("User is already being created or authenticated!"), - wait: true - }); + if(cat.ing){ + cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); return gun; } cat.ing = true; opt = opt || {}; - var act = {}, - u; - act.a = function(pubs) { + var act = {}, u; + act.a = function(pubs){ act.pubs = pubs; - if (pubs && !opt.already) { + if(pubs && !opt.already){ // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. - var ack = { err: Gun.log("User already created!") }; + var ack = {err: Gun.log('User already created!')}; cat.ing = false; cb(ack); gun.leave(); @@ -1152,303 +760,230 @@ } act.salt = Gun.text.random(64); // pseudo-randomly create a salt, then use PBKDF2 function to extend the password with it. SEA.work(pass, act.salt, act.b); // this will take some short amount of time to produce a proof, which slows brute force attacks. - }; - act.b = function(proof) { + } + act.b = function(proof){ act.proof = proof; SEA.pair(act.c); // now we have generated a brand new ECDSA key pair for the user account. - }; - act.c = function(pair) { - var tmp; + } + act.c = function(pair){ var tmp; act.pair = pair || {}; - if ((tmp = cat.root.user)) { + if(tmp = cat.root.user){ tmp._.sea = pair; - tmp.is = { pub: pair.pub, epub: pair.epub, alias: alias }; + tmp.is = {pub: pair.pub, epub: pair.epub, alias: alias}; } // the user's public key doesn't need to be signed. But everything else needs to be signed with it! // we have now automated it! clean up these extra steps now! - act.data = { pub: pair.pub }; + act.data = {pub: pair.pub}; act.d(); - }; - act.d = function() { + } + act.d = function(){ act.data.alias = alias; act.e(); - }; - act.e = function() { - act.data.epub = act.pair.epub; - SEA.encrypt( - { priv: act.pair.priv, epriv: act.pair.epriv }, - act.proof, - act.f, - { raw: 1 } - ); // to keep the private key safe, we AES encrypt it with the proof of work! - }; - act.f = function(auth) { - act.data.auth = JSON.stringify({ ek: auth, s: act.salt }); + } + act.e = function(){ + act.data.epub = act.pair.epub; + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f, {raw:1}); // to keep the private key safe, we AES encrypt it with the proof of work! + } + act.f = function(auth){ + act.data.auth = JSON.stringify({ek: auth, s: act.salt}); act.g(act.data.auth); - }; - act.g = function(auth) { - var tmp; + } + act.g = function(auth){ var tmp; act.data.auth = act.data.auth || auth; - root.get((tmp = "~" + act.pair.pub)).put(act.data); // awesome, now we can actually save the user with their public key as their ID. - root.get("~@" + alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. - setTimeout(function() { - // we should be able to delete this now, right? - cat.ing = false; - cb({ ok: 0, pub: act.pair.pub }); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) - if (noop === cb) { - gun.auth(alias, pass); - } // if no callback is passed, auto-login after signing up. - }, 10); - }; - root.get("~@" + alias).once(act.a); + root.get(tmp = '~'+act.pair.pub).put(act.data); // awesome, now we can actually save the user with their public key as their ID. + root.get('~@'+alias).put(Gun.obj.put({}, tmp, Gun.val.link.ify(tmp))); // next up, we want to associate the alias with the public key. So we add it to the alias list. + setTimeout(function(){ // we should be able to delete this now, right? + cat.ing = false; + cb({ok: 0, pub: act.pair.pub}); // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) + if(noop === cb){ gun.auth(alias, pass) } // if no callback is passed, auto-login after signing up. + },10); + } + root.get('~@'+alias).once(act.a); return gun; - }; + } // now that we have created a user, we want to authenticate them! - User.prototype.auth = function(alias, pass, cb, opt) { - var gun = this, - cat = gun._, - root = gun.back(-1); - cb = cb || function() {}; - if (cat.ing) { - cb({ - err: Gun.log("User is already being created or authenticated!"), - wait: true - }); + User.prototype.auth = function(alias, pass, cb, opt){ + var gun = this, cat = (gun._), root = gun.back(-1); + cb = cb || function(){}; + if(cat.ing){ + cb({err: Gun.log("User is already being created or authenticated!"), wait: true}); return gun; } cat.ing = true; opt = opt || {}; - var pair = - alias && (alias.pub || alias.epub) - ? alias - : pass && (pass.pub || pass.epub) - ? pass - : null; - var act = {}, - u; - act.a = function(data) { - if (!data) { - return act.b(); - } - if (!data.pub) { + var pair = (alias && (alias.pub || alias.epub))? alias : (pass && (pass.pub || pass.epub))? pass : null; + var act = {}, u; + act.a = function(data){ + if(!data){ return act.b() } + if(!data.pub){ var tmp = []; - Gun.node.is(data, function(v) { - tmp.push(v); - }); + Gun.node.is(data, function(v){ tmp.push(v) }) return act.b(tmp); } - if (act.name) { - return act.f(data); - } + if(act.name){ return act.f(data) } act.c((act.data = data).auth); - }; - act.b = function(list) { - var get = (act.list = (act.list || []).concat(list || [])).shift(); - if (u === get) { - if (act.name) { - return act.err( - "Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer." - ); - } - return act.err("Wrong user or password."); + } + act.b = function(list){ + var get = (act.list = (act.list||[]).concat(list||[])).shift(); + if(u === get){ + if(act.name){ return act.err('Your user account is not published for dApps to access, please consider syncing it online, or allowing local access by adding your device as a peer.') } + return act.err('Wrong user or password.') } root.get(get).once(act.a); - }; - act.c = function(auth) { - if (u === auth) { - return act.b(); - } - if (Gun.text.is(auth)) { - return act.c(Gun.obj.ify(auth)); - } // in case of legacy + } + act.c = function(auth){ + if(u === auth){ return act.b() } + if(Gun.text.is(auth)){ return act.c(Gun.obj.ify(auth)) } // in case of legacy SEA.work(pass, (act.auth = auth).s, act.d, act.enc); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force. - }; - act.d = function(proof) { + } + act.d = function(proof){ SEA.decrypt(act.auth.ek, proof, act.e, act.enc); - }; - act.e = function(half) { - if (u === half) { - if (!act.enc) { - // try old format - act.enc = { encode: "utf8" }; + } + act.e = function(half){ + if(u === half){ + if(!act.enc){ // try old format + act.enc = {encode: 'utf8'}; return act.c(act.auth); - } - act.enc = null; // end backwards + } act.enc = null; // end backwards return act.b(); } act.half = half; act.f(act.data); - }; - act.f = function(data) { - if (!data || !data.pub) { - return act.b(); - } + } + act.f = function(data){ + if(!data || !data.pub){ return act.b() } var tmp = act.half || {}; - act.g({ - pub: data.pub, - epub: data.epub, - priv: tmp.priv, - epriv: tmp.epriv - }); - }; - act.g = function(pair) { + act.g({pub: data.pub, epub: data.epub, priv: tmp.priv, epriv: tmp.epriv}); + } + act.g = function(pair){ act.pair = pair; - var user = root._.user, - at = user._; + var user = (root._).user, at = (user._); var tmp = at.tag; var upt = at.opt; - at = user._ = root.get("~" + pair.pub)._; + at = user._ = root.get('~'+pair.pub)._; at.opt = upt; // add our credentials in-memory only to our root user instance - user.is = { pub: pair.pub, epub: pair.epub, alias: alias }; + user.is = {pub: pair.pub, epub: pair.epub, alias: alias}; at.sea = act.pair; cat.ing = false; - try { - if ( - pass && - !Gun.obj.has(Gun.obj.ify(cat.root.graph["~" + pair.pub].auth), ":") - ) { - opt.shuffle = opt.change = pass; - } - } catch (e) {} // migrate UTF8 & Shuffle! - opt.change ? act.z() : cb(at); - if (SEA.window && (gun.back("user")._.opt || opt).remember) { + try{if(pass && !Gun.obj.has(Gun.obj.ify(cat.root.graph['~'+pair.pub].auth), ':')){ opt.shuffle = opt.change = pass; } }catch(e){} // migrate UTF8 & Shuffle! + opt.change? act.z() : cb(at); + if(SEA.window && ((gun.back('user')._).opt||opt).remember){ // TODO: this needs to be modular. - try { - var sS = {}; - sS = window.sessionStorage; - sS.recall = true; - sS.alias = alias; - sS.tmp = pass; - } catch (e) {} + try{var sS = {}; + sS = window.sessionStorage; + sS.recall = true; + sS.alias = alias; + sS.tmp = pass; + }catch(e){} } - try { - root._.on("auth", at); // TODO: Deprecate this, emit on user instead! Update docs when you do. + try{ + (root._).on('auth', at) // TODO: Deprecate this, emit on user instead! Update docs when you do. //at.on('auth', at) // Arrgh, this doesn't work without event "merge" code, but "merge" code causes stack overflow and crashes after logging in & trying to write data. - } catch (e) { + }catch(e){ Gun.log("Your 'auth' callback crashed with:", e); } - }; - act.z = function() { + } + act.z = function(){ // password update so encrypt private key using new pwd + salt act.salt = Gun.text.random(64); // pseudo-random SEA.work(opt.change, act.salt, act.y); - }; - act.y = function(proof) { - SEA.encrypt( - { priv: act.pair.priv, epriv: act.pair.epriv }, - proof, - act.x, - { raw: 1 } - ); - }; - act.x = function(auth) { - act.w(JSON.stringify({ ek: auth, s: act.salt })); - }; - act.w = function(auth) { - if (opt.shuffle) { - // delete in future! - console.log("migrate core account from UTF8 & shuffle"); + } + act.y = function(proof){ + SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x, {raw:1}); + } + act.x = function(auth){ + act.w(JSON.stringify({ek: auth, s: act.salt})); + } + act.w = function(auth){ + if(opt.shuffle){ // delete in future! + console.log('migrate core account from UTF8 & shuffle'); var tmp = Gun.obj.to(act.data); - Gun.obj.del(tmp, "_"); + Gun.obj.del(tmp, '_'); tmp.auth = auth; - root.get("~" + act.pair.pub).put(tmp); + root.get('~'+act.pair.pub).put(tmp); } // end delete - root - .get("~" + act.pair.pub) - .get("auth") - .put(auth, cb); - }; - act.err = function(e) { - var ack = { err: Gun.log(e || "User cannot be found!") }; + root.get('~'+act.pair.pub).get('auth').put(auth, cb); + } + act.err = function(e){ + var ack = {err: Gun.log(e || 'User cannot be found!')}; cat.ing = false; cb(ack); - }; - act.plugin = function(name) { - if (!(act.name = name)) { - return act.err(); - } + } + act.plugin = function(name){ + if(!(act.name = name)){ return act.err() } var tmp = [name]; - if ("~" !== name[0]) { - tmp[1] = "~" + name; - tmp[2] = "~@" + name; + if('~' !== name[0]){ + tmp[1] = '~'+name; + tmp[2] = '~@'+name; } act.b(tmp); - }; - if (pair) { + } + if(pair){ act.g(pair); - } else if (alias) { - root.get("~@" + alias).once(act.a); - } else if (!alias && !pass) { + } else + if(alias){ + root.get('~@'+alias).once(act.a); + } else + if(!alias && !pass){ SEA.name(act.plugin); } return gun; - }; - User.prototype.pair = function() { + } + User.prototype.pair = function(){ console.log("user.pair() IS DEPRECATED AND WILL BE DELETED!!!"); var user = this; - if (!user.is) { - return false; - } + if(!user.is){ return false } return user._.sea; - }; - User.prototype.leave = function(opt, cb) { - var gun = this, - user = gun.back(-1)._.user; - if (user) { + } + User.prototype.leave = function(opt, cb){ + var gun = this, user = (gun.back(-1)._).user; + if(user){ delete user.is; delete user._.is; delete user._.sea; } - if (SEA.window) { - try { - var sS = {}; - sS = window.sessionStorage; - delete sS.alias; - delete sS.tmp; - delete sS.recall; - } catch (e) {} + if(SEA.window){ + try{var sS = {}; + sS = window.sessionStorage; + delete sS.alias; + delete sS.tmp; + delete sS.recall; + }catch(e){}; } return gun; - }; + } // If authenticated user wants to delete his/her account, let's support it! - User.prototype.delete = async function(alias, pass, cb) { - var gun = this, - root = gun.back(-1), - user = gun.back("user"); + User.prototype.delete = async function(alias, pass, cb){ + var gun = this, root = gun.back(-1), user = gun.back('user'); try { - user.auth(alias, pass, function(ack) { - var pub = (user.is || {}).pub; + user.auth(alias, pass, function(ack){ + var pub = (user.is||{}).pub; // Delete user data - user.map().once(function() { - this.put(null); - }); + user.map().once(function(){ this.put(null) }); // Wipe user data from memory user.leave(); - (cb || noop)({ ok: 0 }); + (cb || noop)({ok: 0}); }); } catch (e) { - Gun.log("User.delete failed! Error:", e); + Gun.log('User.delete failed! Error:', e); } return gun; - }; - User.prototype.recall = function(opt, cb) { - var gun = this, - root = gun.back(-1), - tmp; + } + User.prototype.recall = function(opt, cb){ + var gun = this, root = gun.back(-1), tmp; opt = opt || {}; - if (opt && opt.sessionStorage) { - if (SEA.window) { - try { - var sS = {}; - sS = window.sessionStorage; - if (sS) { - root._.opt.remember = true; - (gun.back("user")._.opt || opt).remember = true; - if (sS.recall || (sS.alias && sS.tmp)) { - root.user().auth(sS.alias, sS.tmp, cb); - } + if(opt && opt.sessionStorage){ + if(SEA.window){ + try{var sS = {}; + sS = window.sessionStorage; + if(sS){ + (root._).opt.remember = true; + ((gun.back('user')._).opt||opt).remember = true; + if(sS.recall || (sS.alias && sS.tmp)){ + root.user().auth(sS.alias, sS.tmp, cb); } - } catch (e) {} + } + }catch(e){} } return gun; } @@ -1458,125 +993,81 @@ should expiry be core or a plugin? */ return gun; - }; - User.prototype.alive = async function() { - const gunRoot = this.back(-1); + } + User.prototype.alive = async function(){ + const gunRoot = this.back(-1) try { // All is good. Should we do something more with actual recalled data? - await authRecall(gunRoot); - return gunRoot._.user._; + await authRecall(gunRoot) + return gunRoot._.user._ } catch (e) { - const err = "No session!"; - Gun.log(err); - throw { err }; + const err = 'No session!' + Gun.log(err) + throw { err } } - }; - User.prototype.trust = async function(user) { + } + User.prototype.trust = async function(user){ // TODO: BUG!!! SEA `node` read listener needs to be async, which means core needs to be async too. //gun.get('alice').get('age').trust(bob); if (Gun.is(user)) { - user.get("pub").get((ctx, ev) => { - console.log(ctx, ev); - }); + user.get('pub').get((ctx, ev) => { + console.log(ctx, ev) + }) } - }; - User.prototype.grant = function(to, cb) { - console.log( - "`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!" - ); - var gun = this, - user = gun.back(-1).user(), - pair = user.pair(), - path = ""; - gun.back(function(at) { - if (at.is) { - return; - } - path += at.get || ""; - }); - (async function() { - var enc, - sec = await user - .get("trust") - .get(pair.pub) - .get(path) - .then(); - sec = await SEA.decrypt(sec, pair); - if (!sec) { - sec = SEA.random(16).toString(); - enc = await SEA.encrypt(sec, pair); - user - .get("trust") - .get(pair.pub) - .get(path) - .put(enc); - } - var pub = to.get("pub").then(); - var epub = to.get("epub").then(); - pub = await pub; - epub = await epub; - var dh = await SEA.secret(epub, pair); - enc = await SEA.encrypt(sec, dh); - user - .get("trust") - .get(pub) - .get(path) - .put(enc, cb); - })(); + } + User.prototype.grant = function(to, cb){ + console.log("`.grant` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); + var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); + (async function(){ + var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); + sec = await SEA.decrypt(sec, pair); + if(!sec){ + sec = SEA.random(16).toString(); + enc = await SEA.encrypt(sec, pair); + user.get('trust').get(pair.pub).get(path).put(enc); + } + var pub = to.get('pub').then(); + var epub = to.get('epub').then(); + pub = await pub; epub = await epub; + var dh = await SEA.secret(epub, pair); + enc = await SEA.encrypt(sec, dh); + user.get('trust').get(pub).get(path).put(enc, cb); + }()); return gun; - }; - User.prototype.secret = function(data, cb) { - console.log( - "`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!" - ); - var gun = this, - user = gun.back(-1).user(), - pair = user.pair(), - path = ""; - gun.back(function(at) { - if (at.is) { - return; - } - path += at.get || ""; - }); - (async function() { - var enc, - sec = await user - .get("trust") - .get(pair.pub) - .get(path) - .then(); - sec = await SEA.decrypt(sec, pair); - if (!sec) { - sec = SEA.random(16).toString(); - enc = await SEA.encrypt(sec, pair); - user - .get("trust") - .get(pair.pub) - .get(path) - .put(enc); - } - enc = await SEA.encrypt(data, sec); - gun.put(enc, cb); - })(); + } + User.prototype.secret = function(data, cb){ + console.log("`.secret` API MAY BE DELETED OR CHANGED OR RENAMED, DO NOT USE!"); + var gun = this, user = gun.back(-1).user(), pair = user.pair(), path = ''; + gun.back(function(at){ if(at.is){ return } path += (at.get||'') }); + (async function(){ + var enc, sec = await user.get('trust').get(pair.pub).get(path).then(); + sec = await SEA.decrypt(sec, pair); + if(!sec){ + sec = SEA.random(16).toString(); + enc = await SEA.encrypt(sec, pair); + user.get('trust').get(pair.pub).get(path).put(enc); + } + enc = await SEA.encrypt(data, sec); + gun.put(enc, cb); + }()); return gun; - }; - module.exports = User; - })(USE, "./create"); + } + module.exports = User + })(USE, './create'); - USE(function(module) { - const SEA = USE("./sea"); + ;USE(function(module){ + const SEA = USE('./sea') const Gun = SEA.Gun; // After we have a GUN extension to make user registration/login easy, we then need to handle everything else. // We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change) - Gun.on("opt", function(at) { - if (!at.sea) { - // only add SEA once per instance, on the "at" context. - at.sea = { own: {} }; - at.on("in", security, at); // now listen to all input data, acting as a firewall. - at.on("out", signature, at); // and output listeners, to encrypt outgoing data. - at.on("node", each, at); + Gun.on('opt', function(at){ + if(!at.sea){ // only add SEA once per instance, on the "at" context. + at.sea = {own: {}}; + at.on('in', security, at); // now listen to all input data, acting as a firewall. + at.on('out', signature, at); // and output listeners, to encrypt outgoing data. + at.on('node', each, at); } this.to.next(at); // make sure to call the "next" middleware adapter. }); @@ -1594,207 +1085,140 @@ // Here is a problem: Multiple public keys can "claim" any node's ID, so this is dangerous! // This means we should ONLY trust our "friends" (our key ring) public keys, not any ones. // I have not yet added that to SEA yet in this alpha release. That is coming soon, but beware in the meanwhile! - function each(msg) { - // TODO: Warning: Need to switch to `gun.on('node')`! Do not use `Gun.on('node'` in your apps! + function each(msg){ // TODO: Warning: Need to switch to `gun.on('node')`! Do not use `Gun.on('node'` in your apps! // NOTE: THE SECURITY FUNCTION HAS ALREADY VERIFIED THE DATA!!! // WE DO NOT NEED TO RE-VERIFY AGAIN, JUST TRANSFORM IT TO PLAINTEXT. - var to = this.to, - vertex = msg.$._.put, - c = 0, - d; - Gun.node.is(msg.put, function(val, key, node) { + var to = this.to, vertex = (msg.$._).put, c = 0, d; + Gun.node.is(msg.put, function(val, key, node){ // only process if SEA formatted? var tmp = Gun.obj.ify(val) || noop; - if (u !== tmp[":"]) { + if(u !== tmp[':']){ node[key] = SEA.opt.unpack(tmp); return; } - if (!SEA.opt.check(val)) { - return; - } + if(!SEA.opt.check(val)){ return } c++; // for each property on the node - SEA.verify(val, false, function(data) { - c--; // false just extracts the plain data. - node[key] = SEA.opt.unpack(data, key, node); // transform to plain value. - if (d && !c && (c = -1)) { - to.next(msg); - } + SEA.verify(val, false, function(data){ c--; // false just extracts the plain data. + node[key] = SEA.opt.unpack(data, key, node);; // transform to plain value. + if(d && !c && (c = -1)){ to.next(msg) } }); }); - if ((d = true) && !c) { - to.next(msg); - } + if((d = true) && !c){ to.next(msg) } } // signature handles data output, it is a proxy to the security function. - function signature(msg) { - if ((msg._ || noop).user) { + function signature(msg){ + if((msg._||noop).user){ return this.to.next(msg); } var ctx = this.as; - (msg._ || (msg._ = function() {})).user = ctx.user; + (msg._||(msg._=function(){})).user = ctx.user; security.call(this, msg); } // okay! The security function handles all the heavy lifting. // It needs to deal read and write of input and output of system data, account/public key data, and regular data. // This is broken down into some pretty clear edge cases, let's go over them: - function security(msg) { - var at = this.as, - sea = at.sea, - to = this.to; - if (at.opt.faith && (msg._ || noop).faith) { - // you probably shouldn't have faith in this! + function security(msg){ + var at = this.as, sea = at.sea, to = this.to; + if(at.opt.faith && (msg._||noop).faith){ // you probably shouldn't have faith in this! this.to.next(msg); // why do we allow skipping security? I'm very scared about it actually. return; // but so that way storage adapters that already verified something can get performance boost. This was a community requested feature. If anybody finds an exploit with it, please report immediately. It should only be exploitable if you have XSS control anyways, which if you do, you can bypass security regardless of this. } - if (msg.get) { + if(msg.get){ // if there is a request to read data from us, then... - var soul = msg.get["#"]; - if (soul) { - // for now, only allow direct IDs to be read. - if (typeof soul !== "string") { - return to.next(msg); - } // do not handle lexical cursors. - if ("alias" === soul) { - // Allow reading the list of usernames/aliases in the system? + var soul = msg.get['#']; + if(soul){ // for now, only allow direct IDs to be read. + if(typeof soul !== 'string'){ return to.next(msg) } // do not handle lexical cursors. + if('alias' === soul){ // Allow reading the list of usernames/aliases in the system? return to.next(msg); // yes. - } else if ("~@" === soul.slice(0, 2)) { - // Allow reading the list of public keys associated with an alias? + } else + if('~@' === soul.slice(0,2)){ // Allow reading the list of public keys associated with an alias? return to.next(msg); // yes. - } else { - // Allow reading everything? + } else { // Allow reading everything? return to.next(msg); // yes // TODO: No! Make this a callback/event that people can filter on. } } } - if (msg.put) { + if(msg.put){ // potentially parallel async operations!!! - var check = {}, - each = {}, - u; - each.node = function(node, soul) { - if (Gun.obj.empty(node, "_")) { - return (check["node" + soul] = 0); - } // ignore empty updates, don't reject them. - Gun.obj.map(node, each.way, { soul: soul, node: node }); + var check = {}, each = {}, u; + each.node = function(node, soul){ + if(Gun.obj.empty(node, '_')){ return check['node'+soul] = 0 } // ignore empty updates, don't reject them. + Gun.obj.map(node, each.way, {soul: soul, node: node}); }; - each.way = function(val, key) { - var soul = this.soul, - node = this.node, - tmp; - if ("_" === key) { - return; - } // ignore meta data - if ("~@" === soul) { - // special case for shared system data, the list of aliases. - each.alias(val, key, node, soul); - return; + each.way = function(val, key){ + var soul = this.soul, node = this.node, tmp; + if('_' === key){ return } // ignore meta data + if('~@' === soul){ // special case for shared system data, the list of aliases. + each.alias(val, key, node, soul); return; } - if ("~@" === soul.slice(0, 2)) { - // special case for shared system data, the list of public keys for an alias. - each.pubs(val, key, node, soul); - return; + if('~@' === soul.slice(0,2)){ // special case for shared system data, the list of public keys for an alias. + each.pubs(val, key, node, soul); return; } - if ( - "~" === soul.slice(0, 1) && - 2 === (tmp = soul.slice(1)).split(".").length - ) { - // special case, account data for a public key. - each.pub(val, key, node, soul, tmp, (msg._ || noop).user); - return; + if('~' === soul.slice(0,1) && 2 === (tmp = soul.slice(1)).split('.').length){ // special case, account data for a public key. + each.pub(val, key, node, soul, tmp, (msg._||noop).user); return; } - each.any(val, key, node, soul, (msg._ || noop).user); - return; - return each.end({ err: "No other data allowed!" }); + each.any(val, key, node, soul, (msg._||noop).user); return; + return each.end({err: "No other data allowed!"}); }; - each.alias = function(val, key, node, soul) { - // Example: {_:#~@, ~@alice: {#~@alice}} - if (!val) { - return each.end({ err: "Data must exist!" }); - } // data MUST exist - if ("~@" + key === Gun.val.link.is(val)) { - return (check["alias" + key] = 0); - } // in fact, it must be EXACTLY equal to itself - each.end({ err: "Mismatching alias." }); // if it isn't, reject. + each.alias = function(val, key, node, soul){ // Example: {_:#~@, ~@alice: {#~@alice}} + if(!val){ return each.end({err: "Data must exist!"}) } // data MUST exist + if('~@'+key === Gun.val.link.is(val)){ return check['alias'+key] = 0 } // in fact, it must be EXACTLY equal to itself + each.end({err: "Mismatching alias."}); // if it isn't, reject. }; - each.pubs = function(val, key, node, soul) { - // Example: {_:#~@alice, ~asdf: {#~asdf}} - if (!val) { - return each.end({ err: "Alias must exist!" }); - } // data MUST exist - if (key === Gun.val.link.is(val)) { - return (check["pubs" + soul + key] = 0); - } // and the ID must be EXACTLY equal to its property - each.end({ err: "Alias must match!" }); // that way nobody can tamper with the list of public keys. + each.pubs = function(val, key, node, soul){ // Example: {_:#~@alice, ~asdf: {#~asdf}} + if(!val){ return each.end({err: "Alias must exist!"}) } // data MUST exist + if(key === Gun.val.link.is(val)){ return check['pubs'+soul+key] = 0 } // and the ID must be EXACTLY equal to its property + each.end({err: "Alias must match!"}); // that way nobody can tamper with the list of public keys. }; - each.pub = function(val, key, node, soul, pub, user) { - var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}} - if ("pub" === key) { - if (val === pub) { - return (check["pub" + soul + key] = 0); - } // the account MUST match `pub` property that equals the ID of the public key. - return each.end({ err: "Account must match!" }); + each.pub = function(val, key, node, soul, pub, user){ var tmp; // Example: {_:#~asdf, hello:'world'~fdsa}} + if('pub' === key){ + if(val === pub){ return (check['pub'+soul+key] = 0) } // the account MUST match `pub` property that equals the ID of the public key. + return each.end({err: "Account must match!"}); } - check["user" + soul + key] = 1; - if (Gun.is(msg.$) && user && user.is && pub === user.is.pub) { - SEA.sign( - SEA.opt.prep((tmp = SEA.opt.parse(val)), key, node, soul), - user._.sea, - function(data) { - var rel; - if (u === data) { - return each.end({ err: SEA.err || "Pub signature fail." }); - } - if ((rel = Gun.val.link.is(val))) { - (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; - } - node[key] = JSON.stringify({ - ":": SEA.opt.unpack(data.m), - "~": data.s - }); - check["user" + soul + key] = 0; - each.end({ ok: 1 }); - }, - { check: SEA.opt.pack(tmp, key, node, soul), raw: 1 } - ); + check['user'+soul+key] = 1; + if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ + SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ var rel; + if(u === data){ return each.end({err: SEA.err || 'Pub signature fail.'}) } + if(rel = Gun.val.link.is(val)){ + (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; + } + node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + check['user'+soul+key] = 0; + each.end({ok: 1}); + }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1}); return; } - SEA.verify(SEA.opt.pack(val, key, node, soul), pub, function(data) { - var rel, tmp; + SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel, tmp; data = SEA.opt.unpack(data, key, node); - if (u === data) { - // make sure the signature matches the account it claims to be on. - return each.end({ err: "Unverified data." }); // reject any updates that are signed with a mismatched account. + if(u === data){ // make sure the signature matches the account it claims to be on. + return each.end({err: "Unverified data."}); // reject any updates that are signed with a mismatched account. } - if ((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)) { + if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; } - check["user" + soul + key] = 0; - each.end({ ok: 1 }); + check['user'+soul+key] = 0; + each.end({ok: 1}); }); }; - each.any = function(val, key, node, soul, user) { - var tmp, pub; - if (!(pub = SEA.opt.pub(soul))) { - if (at.opt.secure) { - each.end({ err: "Soul is missing public key at '" + key + "'." }); + each.any = function(val, key, node, soul, user){ var tmp, pub; + if(!(pub = SEA.opt.pub(soul))){ + if(at.opt.secure){ + each.end({err: "Soul is missing public key at '" + key + "'."}); return; } // TODO: Ask community if should auto-sign non user-graph data. - check["any" + soul + key] = 1; - at.on("secure", function(msg) { - this.off(); - check["any" + soul + key] = 0; - if (at.opt.secure) { - msg = null; - } - each.end(msg || { err: "Data cannot be modified." }); - }).on.on("secure", msg); + check['any'+soul+key] = 1; + at.on('secure', function(msg){ this.off(); + check['any'+soul+key] = 0; + if(at.opt.secure){ msg = null } + each.end(msg || {err: "Data cannot be modified."}); + }).on.on('secure', msg); //each.end({err: "Data cannot be modified."}); return; } - if (Gun.is(msg.$) && user && user.is && pub === user.is.pub) { + if(Gun.is(msg.$) && user && user.is && pub === user.is.pub){ /*var other = Gun.obj.map(at.sea.own[soul], function(v, p){ if((user.is||{}).pub !== p){ return p } }); @@ -1802,139 +1226,81 @@ each.any(val, key, node, soul); return; }*/ - check["any" + soul + key] = 1; - SEA.sign( - SEA.opt.prep((tmp = SEA.opt.parse(val)), key, node, soul), - user._.sea, - function(data) { - if (u === data) { - return each.end({ err: "My signature fail." }); - } - node[key] = JSON.stringify({ - ":": SEA.opt.unpack(data.m), - "~": data.s - }); - check["any" + soul + key] = 0; - each.end({ ok: 1 }); - }, - { check: SEA.opt.pack(tmp, key, node, soul), raw: 1 } - ); + check['any'+soul+key] = 1; + SEA.sign(SEA.opt.prep(tmp = SEA.opt.parse(val), key, node, soul), (user._).sea, function(data){ + if(u === data){ return each.end({err: 'My signature fail.'}) } + node[key] = JSON.stringify({':': SEA.opt.unpack(data.m), '~': data.s}); + check['any'+soul+key] = 0; + each.end({ok: 1}); + }, {check: SEA.opt.pack(tmp, key, node, soul), raw: 1}); return; } - check["any" + soul + key] = 1; - SEA.verify(SEA.opt.pack(val, key, node, soul), pub, function(data) { - var rel; + check['any'+soul+key] = 1; + SEA.verify(SEA.opt.pack(val,key,node,soul), pub, function(data){ var rel; data = SEA.opt.unpack(data, key, node); - if (u === data) { - return each.end({ err: "Mismatched owner on '" + key + "'." }); - } // thanks @rogowski ! - if ((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)) { + if(u === data){ return each.end({err: "Mismatched owner on '" + key + "'."}) } // thanks @rogowski ! + if((rel = Gun.val.link.is(data)) && pub === SEA.opt.pub(rel)){ (at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true; } - check["any" + soul + key] = 0; - each.end({ ok: 1 }); + check['any'+soul+key] = 0; + each.end({ok: 1}); }); - }; - each.end = function(ctx) { - // TODO: Can't you just switch this to each.end = cb? - if (each.err) { + } + each.end = function(ctx){ // TODO: Can't you just switch this to each.end = cb? + if(each.err){ return } + if((each.err = ctx.err) || ctx.no){ + console.log('NO!', each.err, msg.put); // 451 mistmached data FOR MARTTI return; } - if ((each.err = ctx.err) || ctx.no) { - console.log("NO!", each.err, msg.put); // 451 mistmached data FOR MARTTI - return; - } - if (!each.end.ed) { - return; - } - if ( - Gun.obj.map(check, function(no) { - if (no) { - return true; - } - }) - ) { - return; - } - (msg._ || {}).user = at.user || security; // already been through firewall, does not need to again on out. + if(!each.end.ed){ return } + if(Gun.obj.map(check, function(no){ + if(no){ return true } + })){ return } + (msg._||{}).user = at.user || security; // already been through firewall, does not need to again on out. to.next(msg); }; Gun.obj.map(msg.put, each.node); - each.end({ end: (each.end.ed = true) }); + each.end({end: each.end.ed = true}); return; // need to manually call next after async. } to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols). } - SEA.opt.pub = function(s) { - if (!s) { - return; - } - s = s.split("~"); - if (!s || !(s = s[1])) { - return; - } - s = s.split("."); - if (!s || 2 > s.length) { - return; - } - s = s.slice(0, 2).join("."); + SEA.opt.pub = function(s){ + if(!s){ return } + s = s.split('~'); + if(!s || !(s = s[1])){ return } + s = s.split('.'); + if(!s || 2 > s.length){ return } + s = s.slice(0,2).join('.'); return s; - }; - SEA.opt.prep = function(d, k, n, s) { - // prep for signing - return { "#": s, ".": k, ":": SEA.opt.parse(d), ">": Gun.state.is(n, k) }; - }; - SEA.opt.pack = function(d, k, n, s) { - // pack for verifying - if (SEA.opt.check(d)) { - return d; - } - var meta = Gun.obj.ify(d) || noop, - sig = meta["~"]; - return sig - ? { - m: { "#": s, ".": k, ":": meta[":"], ">": Gun.state.is(n, k) }, - s: sig - } - : d; - }; - SEA.opt.unpack = function(d, k, n) { - var tmp; - if (u === d) { - return; - } - if (d && u !== (tmp = d[":"])) { - return tmp; - } - if (!k || !n) { - return; - } - if (d === n[k]) { - return d; - } - if (!SEA.opt.check(n[k])) { - return d; - } - var soul = Gun.node.soul(n), - s = Gun.state.is(n, k); - if ( - d && - 4 === d.length && - soul === d[0] && - k === d[1] && - fl(s) === fl(d[3]) - ) { + } + SEA.opt.prep = function(d,k, n,s){ // prep for signing + return {'#':s,'.':k,':':SEA.opt.parse(d),'>':Gun.state.is(n, k)}; + } + SEA.opt.pack = function(d,k, n,s){ // pack for verifying + if(SEA.opt.check(d)){ return d } + var meta = (Gun.obj.ify(d)||noop), sig = meta['~']; + return sig? {m: {'#':s,'.':k,':':meta[':'],'>':Gun.state.is(n, k)}, s: sig} : d; + } + SEA.opt.unpack = function(d, k, n){ var tmp; + if(u === d){ return } + if(d && (u !== (tmp = d[':']))){ return tmp } + if(!k || !n){ return } + if(d === n[k]){ return d } + if(!SEA.opt.check(n[k])){ return d } + var soul = Gun.node.soul(n), s = Gun.state.is(n, k); + if(d && 4 === d.length && soul === d[0] && k === d[1] && fl(s) === fl(d[3])){ return d[2]; } - if (s < SEA.opt.shuffle_attack) { + if(s < SEA.opt.shuffle_attack){ return d; } - }; + } SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019 - var noop = function() {}, - u; + var noop = function(){}, u; var fl = Math.floor; // TODO: Still need to fix inconsistent state issue. var rel_is = Gun.val.rel.is; // TODO: Potential bug? If pub/priv key starts with `-`? IDK how possible. - })(USE, "./index"); -})(); + + })(USE, './index'); +}()); \ No newline at end of file From 2f0d2e3adece0dd4e58d390f22d1484853db9f57 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 10 Sep 2019 14:48:10 -0700 Subject: [PATCH 09/19] version bump for upcoming RAD fixes (currently not all done) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 68d1b740..aa22d6d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.2019.726", + "version": "0.2019.910", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.js", From 71e0be33f73c4fbaca525936eb5eceb718dbdb14 Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Sat, 14 Sep 2019 12:56:48 -0700 Subject: [PATCH 10/19] Switched to webcrypto --- package.json | 8 +-- sea.js | 12 +++- sea/array.js | 51 ++++++++------- sea/buffer.js | 165 ++++++++++++++++++++++++++---------------------- sea/shim.js | 71 +++++++++++---------- test/sea/sea.js | 3 + 6 files changed, 173 insertions(+), 137 deletions(-) diff --git a/package.json b/package.json index aa22d6d4..7ed4f77a 100644 --- a/package.json +++ b/package.json @@ -54,14 +54,14 @@ "ws": "~>7.1.0" }, "optionalDependencies": { - "text-encoding": "^0.7.0", - "node-webcrypto-ossl": "^1.0.47", - "emailjs": "^2.2.0" + "@peculiar/webcrypto": "^1.0.19", + "emailjs": "^2.2.0", + "text-encoding": "^0.7.0" }, "devDependencies": { "aws-sdk": ">=2.153.0", "ip": "^1.1.5", - "mocha": "^5.2.0", + "mocha": "^6.2.0", "panic-manager": "^1.2.0", "panic-server": "^1.1.1", "uglify-js": ">=2.8.22" diff --git a/sea.js b/sea.js index 0a931a6a..1e1fb1be 100644 --- a/sea.js +++ b/sea.js @@ -64,6 +64,11 @@ (_, i) => String.fromCharCode(this[ i + start]) ).join('') } + + function btoa(b) { + return new Buffer(b).toString('base64'); + }; + if (enc === 'base64') { return btoa(this) } @@ -91,6 +96,9 @@ } const input = arguments[0] let buf + function atob(a) { + return new Buffer(a, 'base64').toString('binary'); + }; if (typeof input === 'string') { const enc = arguments[1] || 'utf8' if (enc === 'hex') { @@ -174,7 +182,7 @@ random: (len) => Buffer.from(crypto.randomBytes(len)) }); //try{ - const WebCrypto = USE('node-webcrypto-ossl', 1); + const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); @@ -304,7 +312,7 @@ //SEA.pair = async (data, proof, cb) => { try { SEA.pair = SEA.pair || (async (cb, opt) => { try { - + console.log('SHIM', shim) var ecdhSubtle = shim.ossl || shim.subtle; // First: ECDSA keys for signing/verifying... var sa = await shim.subtle.generateKey(S.ecdsa.pair, true, [ 'sign', 'verify' ]) diff --git a/sea/array.js b/sea/array.js index fecdde5d..91c9a931 100644 --- a/sea/array.js +++ b/sea/array.js @@ -1,24 +1,29 @@ +// This is Array extended to have .toString(['utf8'|'hex'|'base64']) +function SeaArray() {} +Object.assign(SeaArray, { from: Array.from }); +SeaArray.prototype = Object.create(Array.prototype); +SeaArray.prototype.toString = function(enc, start, end) { + enc = enc || "utf8"; + start = start || 0; + const length = this.length; + if (enc === "hex") { + const buf = new Uint8Array(this); + return [...Array(((end && end + 1) || length) - start).keys()] + .map(i => buf[i + start].toString(16).padStart(2, "0")) + .join(""); + } + if (enc === "utf8") { + return Array.from({ length: (end || length) - start }, (_, i) => + String.fromCharCode(this[i + start]) + ).join(""); + } - // This is Array extended to have .toString(['utf8'|'hex'|'base64']) - function SeaArray() {} - Object.assign(SeaArray, { from: Array.from }) - SeaArray.prototype = Object.create(Array.prototype) - SeaArray.prototype.toString = function(enc, start, end) { enc = enc || 'utf8'; start = start || 0; - const length = this.length - if (enc === 'hex') { - const buf = new Uint8Array(this) - return [ ...Array(((end && (end + 1)) || length) - start).keys()] - .map((i) => buf[ i + start ].toString(16).padStart(2, '0')).join('') - } - if (enc === 'utf8') { - return Array.from( - { length: (end || length) - start }, - (_, i) => String.fromCharCode(this[ i + start]) - ).join('') - } - if (enc === 'base64') { - return btoa(this) - } - } - module.exports = SeaArray; - \ No newline at end of file + function btoa(b) { + return new Buffer(b).toString("base64"); + } + + if (enc === "base64") { + return btoa(this); + } +}; +module.exports = SeaArray; diff --git a/sea/buffer.js b/sea/buffer.js index 1854bd1c..bcba634c 100644 --- a/sea/buffer.js +++ b/sea/buffer.js @@ -1,78 +1,95 @@ - - // This is Buffer implementation used in SEA. Functionality is mostly - // compatible with NodeJS 'safe-buffer' and is used for encoding conversions - // between binary and 'hex' | 'utf8' | 'base64' - // See documentation and validation for safe implementation in: - // https://github.com/feross/safe-buffer#update - var SeaArray = require('./array'); - function SafeBuffer(...props) { - console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()') - return SafeBuffer.from(...props) +// This is Buffer implementation used in SEA. Functionality is mostly +// compatible with NodeJS 'safe-buffer' and is used for encoding conversions +// between binary and 'hex' | 'utf8' | 'base64' +// See documentation and validation for safe implementation in: +// https://github.com/feross/safe-buffer#update +var SeaArray = require("./array"); +function SafeBuffer(...props) { + console.warn("new SafeBuffer() is depreciated, please use SafeBuffer.from()"); + return SafeBuffer.from(...props); +} +SafeBuffer.prototype = Object.create(Array.prototype); +Object.assign(SafeBuffer, { + // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' + from() { + if (!Object.keys(arguments).length) { + throw new TypeError( + "First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object." + ); } - SafeBuffer.prototype = Object.create(Array.prototype) - Object.assign(SafeBuffer, { - // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' - from() { - if (!Object.keys(arguments).length) { - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + const input = arguments[0]; + let buf; + function atob(a) { + return new Buffer(a, "base64").toString("binary"); + } + if (typeof input === "string") { + const enc = arguments[1] || "utf8"; + if (enc === "hex") { + const bytes = input + .match(/([\da-fA-F]{2})/g) + .map(byte => parseInt(byte, 16)); + if (!bytes || !bytes.length) { + throw new TypeError("Invalid first argument for type 'hex'."); } - const input = arguments[0] - let buf - if (typeof input === 'string') { - const enc = arguments[1] || 'utf8' - if (enc === 'hex') { - const bytes = input.match(/([\da-fA-F]{2})/g) - .map((byte) => parseInt(byte, 16)) - if (!bytes || !bytes.length) { - throw new TypeError('Invalid first argument for type \'hex\'.') - } - buf = SeaArray.from(bytes) - } else if (enc === 'utf8') { - const length = input.length - const words = new Uint16Array(length) - Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i)) - buf = SeaArray.from(words) - } else if (enc === 'base64') { - const dec = atob(input) - const length = dec.length - const bytes = new Uint8Array(length) - Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i)) - buf = SeaArray.from(bytes) - } else if (enc === 'binary') { - buf = SeaArray.from(input) - } else { - console.info('SafeBuffer.from unknown encoding: '+enc) - } - return buf - } - const byteLength = input.byteLength // what is going on here? FOR MARTTI - const length = input.byteLength ? input.byteLength : input.length - if (length) { - let buf - if (input instanceof ArrayBuffer) { - buf = new Uint8Array(input) - } - return SeaArray.from(buf || input) - } - }, - // This is 'safe-buffer.alloc' sans encoding support - alloc(length, fill = 0 /*, enc*/ ) { - return SeaArray.from(new Uint8Array(Array.from({ length: length }, () => fill))) - }, - // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! - allocUnsafe(length) { - return SeaArray.from(new Uint8Array(Array.from({ length : length }))) - }, - // This puts together array of array like members - concat(arr) { // octet array - if (!Array.isArray(arr)) { - throw new TypeError('First argument must be Array containing ArrayBuffer or Uint8Array instances.') - } - return SeaArray.from(arr.reduce((ret, item) => ret.concat(Array.from(item)), [])) + buf = SeaArray.from(bytes); + } else if (enc === "utf8") { + const length = input.length; + const words = new Uint16Array(length); + Array.from( + { length: length }, + (_, i) => (words[i] = input.charCodeAt(i)) + ); + buf = SeaArray.from(words); + } else if (enc === "base64") { + const dec = atob(input); + const length = dec.length; + const bytes = new Uint8Array(length); + Array.from( + { length: length }, + (_, i) => (bytes[i] = dec.charCodeAt(i)) + ); + buf = SeaArray.from(bytes); + } else if (enc === "binary") { + buf = SeaArray.from(input); + } else { + console.info("SafeBuffer.from unknown encoding: " + enc); } - }) - SafeBuffer.prototype.from = SafeBuffer.from - SafeBuffer.prototype.toString = SeaArray.prototype.toString + return buf; + } + const byteLength = input.byteLength; // what is going on here? FOR MARTTI + const length = input.byteLength ? input.byteLength : input.length; + if (length) { + let buf; + if (input instanceof ArrayBuffer) { + buf = new Uint8Array(input); + } + return SeaArray.from(buf || input); + } + }, + // This is 'safe-buffer.alloc' sans encoding support + alloc(length, fill = 0 /*, enc*/) { + return SeaArray.from( + new Uint8Array(Array.from({ length: length }, () => fill)) + ); + }, + // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! + allocUnsafe(length) { + return SeaArray.from(new Uint8Array(Array.from({ length: length }))); + }, + // This puts together array of array like members + concat(arr) { + // octet array + if (!Array.isArray(arr)) { + throw new TypeError( + "First argument must be Array containing ArrayBuffer or Uint8Array instances." + ); + } + return SeaArray.from( + arr.reduce((ret, item) => ret.concat(Array.from(item)), []) + ); + } +}); +SafeBuffer.prototype.from = SafeBuffer.from; +SafeBuffer.prototype.toString = SeaArray.prototype.toString; - module.exports = SafeBuffer; - \ No newline at end of file +module.exports = SafeBuffer; diff --git a/sea/shim.js b/sea/shim.js index b6026e8c..930fef9e 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -1,36 +1,39 @@ +const SEA = require("./root"); +const Buffer = require("./buffer"); +const api = { Buffer: Buffer }; +var o = {}; - const SEA = require('./root') - const Buffer = require('./buffer') - const api = {Buffer: Buffer} - var o = {}; +if (SEA.window) { + api.crypto = window.crypto || window.msCrypto; + api.subtle = (api.crypto || o).subtle || (api.crypto || o).webkitSubtle; + api.TextEncoder = window.TextEncoder; + api.TextDecoder = window.TextDecoder; + api.random = len => + Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))); +} +if (!api.crypto) { + try { + var crypto = require("crypto", 1); + const { TextEncoder, TextDecoder } = require("text-encoding", 1); + Object.assign(api, { + crypto, + //subtle, + TextEncoder, + TextDecoder, + random: len => Buffer.from(crypto.randomBytes(len)) + }); + //try{ + const { Crypto: WebCrypto } = require("@peculiar/webcrypto", 1); + api.ossl = api.subtle = new WebCrypto({ directory: "ossl" }).subtle; // ECDH + //}catch(e){ + //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); + //} + } catch (e) { + console.log( + "node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!" + ); + OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; + } +} - if(SEA.window){ - api.crypto = window.crypto || window.msCrypto; - api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle; - api.TextEncoder = window.TextEncoder; - api.TextDecoder = window.TextDecoder; - api.random = (len) => Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) - } - if(!api.crypto){try{ - var crypto = require('crypto', 1); - const { TextEncoder, TextDecoder } = require('text-encoding', 1) - Object.assign(api, { - crypto, - //subtle, - TextEncoder, - TextDecoder, - random: (len) => Buffer.from(crypto.randomBytes(len)) - }); - //try{ - const WebCrypto = require('node-webcrypto-ossl', 1); - api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH - //}catch(e){ - //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); - //} - }catch(e){ - console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!"); - OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; - }} - - module.exports = api - \ No newline at end of file +module.exports = api; diff --git a/test/sea/sea.js b/test/sea/sea.js index e4e5f70e..bd7f59c2 100644 --- a/test/sea/sea.js +++ b/test/sea/sea.js @@ -1,5 +1,8 @@ var root; var Gun; +function atob(a) { + return new Buffer(a, 'base64').toString('binary'); +}; (function(){ var env; if(typeof global !== 'undefined'){ env = global } From 0b0370215283e1bdf5ca7e632a26732d89a5060b Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Sat, 14 Sep 2019 13:08:40 -0700 Subject: [PATCH 11/19] Update package-lock for travis --- package-lock.json | 974 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 911 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ab50c2f..c25fcdf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,59 @@ { "name": "gun", - "version": "0.2019.711", + "version": "0.2019.910", "lockfileVersion": 1, "requires": true, "dependencies": { + "@peculiar/asn1-schema": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-1.0.3.tgz", + "integrity": "sha512-Tfgj9eNJ6cTKEtEuidKenLHMx/Q5M8KEE9hnohHqvdpqHJXWYr5RlT3GjAHPjGXy5+mr7sSfuXfzE6aAkEGN7A==", + "optional": true, + "requires": { + "asn1js": "^2.0.22", + "tslib": "^1.9.3" + } + }, + "@peculiar/json-schema": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.5.tgz", + "integrity": "sha512-y5XYA3pf9+c+YKVpWnPtQbNmlNCs2ehNHyMLJvq4K5Fjwc1N64YGy7MNecKW3uYLga+sqbGTQSUdOdlnaRRbpA==", + "optional": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "@peculiar/webcrypto": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.0.19.tgz", + "integrity": "sha512-+lF69A18LJBLp0/gJIQatCARLah6cTUmLwY0Cdab0zsk+Z53BcpjKQyyP4LIN8oW601ZXv28mWEQ4Cm7MllF6w==", + "optional": true, + "requires": { + "@peculiar/asn1-schema": "^1.0.3", + "@peculiar/json-schema": "^1.1.5", + "asn1js": "^2.0.26", + "pvtsutils": "^1.0.6", + "tslib": "^1.10.0", + "webcrypto-core": "^1.0.14" + }, + "dependencies": { + "webcrypto-core": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.0.14.tgz", + "integrity": "sha512-iGZQcH/o3Jv6mpvCbzan6uAcUcLTTnUCil6RVYakcNh5/QXIKRRC06EFxHru9lHgVKucZy3gG4OBiup0IsOr0g==", + "optional": true, + "requires": { + "pvtsutils": "^1.0.4", + "tslib": "^1.10.0" + } + } + } + }, + "@types/node": { + "version": "10.14.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.18.tgz", + "integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ==" + }, "addressparser": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", @@ -16,12 +66,50 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "arraybuffer.slice": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", "dev": true }, + "asn1js": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.0.26.tgz", + "integrity": "sha512-yG89F0j9B4B0MKIcFyWWxnpZPLaNTjCj4tkE3fjbAoo0qmpGw0PYYqSbX/4ebnd9Icn8ZgK4K1fvDyEtW1JYtQ==", + "requires": { + "pvutils": "^1.0.17" + } + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -129,10 +217,64 @@ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "component-bind": { @@ -165,6 +307,43 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -198,6 +377,21 @@ "text-encoding": "^0.7.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, "engine.io": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", @@ -322,28 +516,117 @@ "wtf-8": "1.0.0" } }, + "es-abstract": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", + "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", "dev": true }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -360,6 +643,15 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-binary": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", @@ -389,10 +681,16 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "ieee754": { @@ -418,9 +716,15 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "ip": { @@ -429,36 +733,148 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", "dev": true }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", "dev": true }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -474,6 +890,12 @@ "mime-db": "~1.33.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -486,76 +908,92 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", + "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "find-up": "3.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.2.2", + "yargs-parser": "13.0.0", + "yargs-unparser": "1.5.0" } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "optional": true - }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", "dev": true }, - "node-webcrypto-ossl": { - "version": "1.0.47", - "resolved": "https://registry.npmjs.org/node-webcrypto-ossl/-/node-webcrypto-ossl-1.0.47.tgz", - "integrity": "sha512-73q5ClXxhr7c1LE5dYajdnCVAPr0dhceX/qkATmJGQWyn7xTLgW9s727Bep/6JPqdnx5v7aBraPc+1c2nqjctw==", - "optional": true, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, "requires": { - "mkdirp": "^0.5.1", - "nan": "^2.13.2", - "tslib": "^1.9.3", - "webcrypto-core": "^0.1.26" + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" } }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, "object-assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", @@ -568,6 +1006,40 @@ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -583,6 +1055,59 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "panic-client": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/panic-client/-/panic-client-1.0.2.tgz", @@ -653,24 +1178,60 @@ "better-assert": "~1.0.0" } }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "platform": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.1.tgz", "integrity": "sha1-SSIQiSM1vTExwKCN2i2T7DVD5CM=", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", "dev": true }, + "pvtsutils": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.6.tgz", + "integrity": "sha512-0yNrOdJyLE7FZzmeEHTKanwBr5XbmDAd020cKa4ZiTYuGMBYBZmq7vHOhcOqhVllh6gghDBbaz1lnVdOqiB7cw==", + "requires": { + "@types/node": "^10.14.17", + "tslib": "^1.10.0" + } + }, + "pvutils": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz", + "integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==" + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -683,12 +1244,57 @@ "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", "optional": true }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", "dev": true }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "socket.io": { "version": "1.7.4", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", @@ -831,10 +1437,67 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -855,8 +1518,7 @@ "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "optional": true + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" }, "uglify-js": { "version": "3.3.24", @@ -892,13 +1554,75 @@ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", "dev": true }, - "webcrypto-core": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-0.1.26.tgz", - "integrity": "sha512-BZVgJZkkHyuz8loKvsaOKiBDXDpmMZf5xG4QAOlSeYdXlFUl9c1FRrVnAXcOdb4fTHMG+TRu81odJwwSfKnWTA==", - "optional": true, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { - "tslib": "^1.7.1" + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } } }, "wrappy": { @@ -946,6 +1670,130 @@ "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", "dev": true }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", + "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", + "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", + "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.11", + "yargs": "^12.0.5" + }, + "dependencies": { + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", From 7b583f3b41df151c5f2c7f72d1768eb72ed8aaff Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Sat, 14 Sep 2019 13:13:40 -0700 Subject: [PATCH 12/19] Remove unnecessary console.log --- sea.js | 1 - 1 file changed, 1 deletion(-) diff --git a/sea.js b/sea.js index 1e1fb1be..969bc43d 100644 --- a/sea.js +++ b/sea.js @@ -312,7 +312,6 @@ //SEA.pair = async (data, proof, cb) => { try { SEA.pair = SEA.pair || (async (cb, opt) => { try { - console.log('SHIM', shim) var ecdhSubtle = shim.ossl || shim.subtle; // First: ECDSA keys for signing/verifying... var sa = await shim.subtle.generateKey(S.ecdsa.pair, true, [ 'sign', 'verify' ]) From 7d7b11f9b80b3ee2a504fd294bf6b15e91d0b1cc Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Sat, 14 Sep 2019 13:19:27 -0700 Subject: [PATCH 13/19] Reset unnecessary prettier changes --- sea.js | 11 +--- sea/array.js | 51 +++++++-------- sea/buffer.js | 171 +++++++++++++++++++++++--------------------------- sea/shim.js | 71 ++++++++++----------- 4 files changed, 136 insertions(+), 168 deletions(-) diff --git a/sea.js b/sea.js index 969bc43d..0a931a6a 100644 --- a/sea.js +++ b/sea.js @@ -64,11 +64,6 @@ (_, i) => String.fromCharCode(this[ i + start]) ).join('') } - - function btoa(b) { - return new Buffer(b).toString('base64'); - }; - if (enc === 'base64') { return btoa(this) } @@ -96,9 +91,6 @@ } const input = arguments[0] let buf - function atob(a) { - return new Buffer(a, 'base64').toString('binary'); - }; if (typeof input === 'string') { const enc = arguments[1] || 'utf8' if (enc === 'hex') { @@ -182,7 +174,7 @@ random: (len) => Buffer.from(crypto.randomBytes(len)) }); //try{ - const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); + const WebCrypto = USE('node-webcrypto-ossl', 1); api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); @@ -312,6 +304,7 @@ //SEA.pair = async (data, proof, cb) => { try { SEA.pair = SEA.pair || (async (cb, opt) => { try { + var ecdhSubtle = shim.ossl || shim.subtle; // First: ECDSA keys for signing/verifying... var sa = await shim.subtle.generateKey(S.ecdsa.pair, true, [ 'sign', 'verify' ]) diff --git a/sea/array.js b/sea/array.js index 91c9a931..fecdde5d 100644 --- a/sea/array.js +++ b/sea/array.js @@ -1,29 +1,24 @@ -// This is Array extended to have .toString(['utf8'|'hex'|'base64']) -function SeaArray() {} -Object.assign(SeaArray, { from: Array.from }); -SeaArray.prototype = Object.create(Array.prototype); -SeaArray.prototype.toString = function(enc, start, end) { - enc = enc || "utf8"; - start = start || 0; - const length = this.length; - if (enc === "hex") { - const buf = new Uint8Array(this); - return [...Array(((end && end + 1) || length) - start).keys()] - .map(i => buf[i + start].toString(16).padStart(2, "0")) - .join(""); - } - if (enc === "utf8") { - return Array.from({ length: (end || length) - start }, (_, i) => - String.fromCharCode(this[i + start]) - ).join(""); - } - function btoa(b) { - return new Buffer(b).toString("base64"); - } - - if (enc === "base64") { - return btoa(this); - } -}; -module.exports = SeaArray; + // This is Array extended to have .toString(['utf8'|'hex'|'base64']) + function SeaArray() {} + Object.assign(SeaArray, { from: Array.from }) + SeaArray.prototype = Object.create(Array.prototype) + SeaArray.prototype.toString = function(enc, start, end) { enc = enc || 'utf8'; start = start || 0; + const length = this.length + if (enc === 'hex') { + const buf = new Uint8Array(this) + return [ ...Array(((end && (end + 1)) || length) - start).keys()] + .map((i) => buf[ i + start ].toString(16).padStart(2, '0')).join('') + } + if (enc === 'utf8') { + return Array.from( + { length: (end || length) - start }, + (_, i) => String.fromCharCode(this[ i + start]) + ).join('') + } + if (enc === 'base64') { + return btoa(this) + } + } + module.exports = SeaArray; + \ No newline at end of file diff --git a/sea/buffer.js b/sea/buffer.js index bcba634c..1854bd1c 100644 --- a/sea/buffer.js +++ b/sea/buffer.js @@ -1,95 +1,78 @@ -// This is Buffer implementation used in SEA. Functionality is mostly -// compatible with NodeJS 'safe-buffer' and is used for encoding conversions -// between binary and 'hex' | 'utf8' | 'base64' -// See documentation and validation for safe implementation in: -// https://github.com/feross/safe-buffer#update -var SeaArray = require("./array"); -function SafeBuffer(...props) { - console.warn("new SafeBuffer() is depreciated, please use SafeBuffer.from()"); - return SafeBuffer.from(...props); -} -SafeBuffer.prototype = Object.create(Array.prototype); -Object.assign(SafeBuffer, { - // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' - from() { - if (!Object.keys(arguments).length) { - throw new TypeError( - "First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object." - ); - } - const input = arguments[0]; - let buf; - function atob(a) { - return new Buffer(a, "base64").toString("binary"); - } - if (typeof input === "string") { - const enc = arguments[1] || "utf8"; - if (enc === "hex") { - const bytes = input - .match(/([\da-fA-F]{2})/g) - .map(byte => parseInt(byte, 16)); - if (!bytes || !bytes.length) { - throw new TypeError("Invalid first argument for type 'hex'."); - } - buf = SeaArray.from(bytes); - } else if (enc === "utf8") { - const length = input.length; - const words = new Uint16Array(length); - Array.from( - { length: length }, - (_, i) => (words[i] = input.charCodeAt(i)) - ); - buf = SeaArray.from(words); - } else if (enc === "base64") { - const dec = atob(input); - const length = dec.length; - const bytes = new Uint8Array(length); - Array.from( - { length: length }, - (_, i) => (bytes[i] = dec.charCodeAt(i)) - ); - buf = SeaArray.from(bytes); - } else if (enc === "binary") { - buf = SeaArray.from(input); - } else { - console.info("SafeBuffer.from unknown encoding: " + enc); - } - return buf; - } - const byteLength = input.byteLength; // what is going on here? FOR MARTTI - const length = input.byteLength ? input.byteLength : input.length; - if (length) { - let buf; - if (input instanceof ArrayBuffer) { - buf = new Uint8Array(input); - } - return SeaArray.from(buf || input); - } - }, - // This is 'safe-buffer.alloc' sans encoding support - alloc(length, fill = 0 /*, enc*/) { - return SeaArray.from( - new Uint8Array(Array.from({ length: length }, () => fill)) - ); - }, - // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! - allocUnsafe(length) { - return SeaArray.from(new Uint8Array(Array.from({ length: length }))); - }, - // This puts together array of array like members - concat(arr) { - // octet array - if (!Array.isArray(arr)) { - throw new TypeError( - "First argument must be Array containing ArrayBuffer or Uint8Array instances." - ); - } - return SeaArray.from( - arr.reduce((ret, item) => ret.concat(Array.from(item)), []) - ); - } -}); -SafeBuffer.prototype.from = SafeBuffer.from; -SafeBuffer.prototype.toString = SeaArray.prototype.toString; -module.exports = SafeBuffer; + // This is Buffer implementation used in SEA. Functionality is mostly + // compatible with NodeJS 'safe-buffer' and is used for encoding conversions + // between binary and 'hex' | 'utf8' | 'base64' + // See documentation and validation for safe implementation in: + // https://github.com/feross/safe-buffer#update + var SeaArray = require('./array'); + function SafeBuffer(...props) { + console.warn('new SafeBuffer() is depreciated, please use SafeBuffer.from()') + return SafeBuffer.from(...props) + } + SafeBuffer.prototype = Object.create(Array.prototype) + Object.assign(SafeBuffer, { + // (data, enc) where typeof data === 'string' then enc === 'utf8'|'hex'|'base64' + from() { + if (!Object.keys(arguments).length) { + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + } + const input = arguments[0] + let buf + if (typeof input === 'string') { + const enc = arguments[1] || 'utf8' + if (enc === 'hex') { + const bytes = input.match(/([\da-fA-F]{2})/g) + .map((byte) => parseInt(byte, 16)) + if (!bytes || !bytes.length) { + throw new TypeError('Invalid first argument for type \'hex\'.') + } + buf = SeaArray.from(bytes) + } else if (enc === 'utf8') { + const length = input.length + const words = new Uint16Array(length) + Array.from({ length: length }, (_, i) => words[i] = input.charCodeAt(i)) + buf = SeaArray.from(words) + } else if (enc === 'base64') { + const dec = atob(input) + const length = dec.length + const bytes = new Uint8Array(length) + Array.from({ length: length }, (_, i) => bytes[i] = dec.charCodeAt(i)) + buf = SeaArray.from(bytes) + } else if (enc === 'binary') { + buf = SeaArray.from(input) + } else { + console.info('SafeBuffer.from unknown encoding: '+enc) + } + return buf + } + const byteLength = input.byteLength // what is going on here? FOR MARTTI + const length = input.byteLength ? input.byteLength : input.length + if (length) { + let buf + if (input instanceof ArrayBuffer) { + buf = new Uint8Array(input) + } + return SeaArray.from(buf || input) + } + }, + // This is 'safe-buffer.alloc' sans encoding support + alloc(length, fill = 0 /*, enc*/ ) { + return SeaArray.from(new Uint8Array(Array.from({ length: length }, () => fill))) + }, + // This is normal UNSAFE 'buffer.alloc' or 'new Buffer(length)' - don't use! + allocUnsafe(length) { + return SeaArray.from(new Uint8Array(Array.from({ length : length }))) + }, + // This puts together array of array like members + concat(arr) { // octet array + if (!Array.isArray(arr)) { + throw new TypeError('First argument must be Array containing ArrayBuffer or Uint8Array instances.') + } + return SeaArray.from(arr.reduce((ret, item) => ret.concat(Array.from(item)), [])) + } + }) + SafeBuffer.prototype.from = SafeBuffer.from + SafeBuffer.prototype.toString = SeaArray.prototype.toString + + module.exports = SafeBuffer; + \ No newline at end of file diff --git a/sea/shim.js b/sea/shim.js index 930fef9e..b6026e8c 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -1,39 +1,36 @@ -const SEA = require("./root"); -const Buffer = require("./buffer"); -const api = { Buffer: Buffer }; -var o = {}; -if (SEA.window) { - api.crypto = window.crypto || window.msCrypto; - api.subtle = (api.crypto || o).subtle || (api.crypto || o).webkitSubtle; - api.TextEncoder = window.TextEncoder; - api.TextDecoder = window.TextDecoder; - api.random = len => - Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))); -} -if (!api.crypto) { - try { - var crypto = require("crypto", 1); - const { TextEncoder, TextDecoder } = require("text-encoding", 1); - Object.assign(api, { - crypto, - //subtle, - TextEncoder, - TextDecoder, - random: len => Buffer.from(crypto.randomBytes(len)) - }); - //try{ - const { Crypto: WebCrypto } = require("@peculiar/webcrypto", 1); - api.ossl = api.subtle = new WebCrypto({ directory: "ossl" }).subtle; // ECDH - //}catch(e){ - //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); - //} - } catch (e) { - console.log( - "node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!" - ); - OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; - } -} + const SEA = require('./root') + const Buffer = require('./buffer') + const api = {Buffer: Buffer} + var o = {}; -module.exports = api; + if(SEA.window){ + api.crypto = window.crypto || window.msCrypto; + api.subtle = (api.crypto||o).subtle || (api.crypto||o).webkitSubtle; + api.TextEncoder = window.TextEncoder; + api.TextDecoder = window.TextDecoder; + api.random = (len) => Buffer.from(api.crypto.getRandomValues(new Uint8Array(Buffer.alloc(len)))) + } + if(!api.crypto){try{ + var crypto = require('crypto', 1); + const { TextEncoder, TextDecoder } = require('text-encoding', 1) + Object.assign(api, { + crypto, + //subtle, + TextEncoder, + TextDecoder, + random: (len) => Buffer.from(crypto.randomBytes(len)) + }); + //try{ + const WebCrypto = require('node-webcrypto-ossl', 1); + api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH + //}catch(e){ + //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); + //} + }catch(e){ + console.log("node-webcrypto-ossl and text-encoding may not be included by default, please add it to your package.json!"); + OSSL_WEBCRYPTO_OR_TEXT_ENCODING_NOT_INSTALLED; + }} + + module.exports = api + \ No newline at end of file From cf642b75d119435692bbef068f3b241beded0dee Mon Sep 17 00:00:00 2001 From: Marcus Bernales Date: Sat, 14 Sep 2019 13:20:21 -0700 Subject: [PATCH 14/19] Brought back new changes --- sea.js | 9 ++++++++- sea/array.js | 4 +++- sea/buffer.js | 4 +++- sea/shim.js | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/sea.js b/sea.js index 0a931a6a..f0a9725f 100644 --- a/sea.js +++ b/sea.js @@ -17,6 +17,13 @@ } if(typeof module !== "undefined"){ var common = module } /* UNBUILD */ + function atob(a) { + return new Buffer(a, 'base64').toString('binary'); + }; + + function btoa(b) { + return new Buffer(b).toString('base64'); + }; ;USE(function(module){ // Security, Encryption, and Authorization: SEA.js @@ -174,7 +181,7 @@ random: (len) => Buffer.from(crypto.randomBytes(len)) }); //try{ - const WebCrypto = USE('node-webcrypto-ossl', 1); + const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); diff --git a/sea/array.js b/sea/array.js index fecdde5d..d10c983c 100644 --- a/sea/array.js +++ b/sea/array.js @@ -1,4 +1,6 @@ - + function btoa(b) { + return new Buffer(b).toString('base64'); + }; // This is Array extended to have .toString(['utf8'|'hex'|'base64']) function SeaArray() {} Object.assign(SeaArray, { from: Array.from }) diff --git a/sea/buffer.js b/sea/buffer.js index 1854bd1c..37f753b4 100644 --- a/sea/buffer.js +++ b/sea/buffer.js @@ -1,4 +1,6 @@ - + function atob(a) { + return new Buffer(a, 'base64').toString('binary'); + }; // This is Buffer implementation used in SEA. Functionality is mostly // compatible with NodeJS 'safe-buffer' and is used for encoding conversions // between binary and 'hex' | 'utf8' | 'base64' diff --git a/sea/shim.js b/sea/shim.js index b6026e8c..21d94355 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -22,7 +22,7 @@ random: (len) => Buffer.from(crypto.randomBytes(len)) }); //try{ - const WebCrypto = require('node-webcrypto-ossl', 1); + const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); From 12d61ace2c56df545da09ad857f5ada72c69f320 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 16 Sep 2019 10:04:38 -0700 Subject: [PATCH 15/19] DROPPING NODEJS 8 SUPPORT!!!! --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4cf6f163..9ae50c30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,7 @@ branches: except: - debug node_js: - - 8 - 10 cache: directories: - - node_modules \ No newline at end of file + - node_modules From 4fb04b8f5345dd2c20d5ce69b0a4ee91bf5bfacf Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 16 Sep 2019 12:36:18 -0700 Subject: [PATCH 16/19] base64 shim --- package.json | 2 +- sea.js | 17 ++++++++++------- test/sea/sea.js | 3 --- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 7ed4f77a..cee14d76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.2019.910", + "version": "0.2019.915", "description": "A realtime, decentralized, offline-first, graph data synchronization engine.", "main": "index.js", "browser": "gun.js", diff --git a/sea.js b/sea.js index f0a9725f..ee2fbf8f 100644 --- a/sea.js +++ b/sea.js @@ -17,13 +17,6 @@ } if(typeof module !== "undefined"){ var common = module } /* UNBUILD */ - function atob(a) { - return new Buffer(a, 'base64').toString('binary'); - }; - - function btoa(b) { - return new Buffer(b).toString('base64'); - }; ;USE(function(module){ // Security, Encryption, and Authorization: SEA.js @@ -54,6 +47,15 @@ })(USE, './https'); ;USE(function(module){ + if(typeof global !== "undefined"){ + var g = global; + g.btoa = function (data) { return Buffer.from(data, "binary").toString("base64"); }; + g.atob = function (data) { return Buffer.from(data, "base64").toString("binary"); }; + } + })(USE, './base64'); + + ;USE(function(module){ + USE('./base64'); // This is Array extended to have .toString(['utf8'|'hex'|'base64']) function SeaArray() {} Object.assign(SeaArray, { from: Array.from }) @@ -79,6 +81,7 @@ })(USE, './array'); ;USE(function(module){ + USE('./base64'); // This is Buffer implementation used in SEA. Functionality is mostly // compatible with NodeJS 'safe-buffer' and is used for encoding conversions // between binary and 'hex' | 'utf8' | 'base64' diff --git a/test/sea/sea.js b/test/sea/sea.js index bd7f59c2..e4e5f70e 100644 --- a/test/sea/sea.js +++ b/test/sea/sea.js @@ -1,8 +1,5 @@ var root; var Gun; -function atob(a) { - return new Buffer(a, 'base64').toString('binary'); -}; (function(){ var env; if(typeof global !== 'undefined'){ env = global } From 99ed43f5c47b9266ad1d41a0de20e8aff016efdb Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Mon, 16 Sep 2019 13:59:44 -0700 Subject: [PATCH 17/19] console.debug -> console.only & unbuild --- gun.js | 2 +- gun.min.js | 2 +- sea/array.js | 5 ++--- sea/base64.js | 7 +++++++ sea/buffer.js | 5 ++--- sea/secret.js | 4 ++-- sea/shim.js | 2 +- src/adapters/localStorage.js | 2 +- src/get.js | 19 +++++++++++++------ src/put.js | 8 +++++--- src/root.js | 2 +- 11 files changed, 36 insertions(+), 22 deletions(-) create mode 100644 sea/base64.js diff --git a/gun.js b/gun.js index 8c2b71f5..851a01f3 100644 --- a/gun.js +++ b/gun.js @@ -858,7 +858,7 @@ var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is; var empty = {}, u; - console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) }; + console.only = function(i, s){ return (console.only.i && i === console.only.i && console.only.i++) && (console.log.apply(console, arguments) || s) }; Gun.log = function(){ return (!Gun.log.off && console.log.apply(console, arguments)), [].slice.call(arguments).join(' ') } Gun.log.once = function(w,s,o){ return (o = Gun.log.once)[w] = o[w] || 0, o[w]++ || Gun.log(s) } diff --git a/gun.min.js b/gun.min.js index bf1a6552..274f7345 100644 --- a/gun.min.js +++ b/gun.min.js @@ -1 +1 @@ -!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var b=(t=t||{}).console||{log:function(){}};function _(o,t){return t?require(o):o.slice?_[e(o)]:function(t,n){o(t={exports:{}}),_[e(n)]=t.exports};function e(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var o=module;_(function(t){var p={fn:{is:function(t){return!!t&&"function"==typeof t}}};p.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},p.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},p.text={is:function(t){return"string"==typeof t}},p.text.ify=function(t){return p.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},p.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||e===n["="]&&(o=n["*"]||n[">"]||n["<"],t.slice(0,(o||"").length)===o||e===n["*"]&&(e!==n[">"]&&e!==n["<"]?t>=n[">"]&&t<=n["<"]:e!==n[">"]&&t>=n[">"]||e!==n["<"]&&t<=n["<"])))},p.list={is:function(t){return t instanceof Array}},p.list.slit=Array.prototype.slice,p.list.sort=function(o){return function(t,n){return t&&n?(t=t[o])<(n=n[o])?-1:n",s.drift=0,s.is=function(t,n,o){var e=n&&t&&t[m]&&t[m][s._]||o;if(e)return g(e=e[n])?e:-1/0},s.lex=function(){return s().toString(36).replace(".","")},s.ify=function(t,n,o,e,i){if(!t||!t[m]){if(!i)return;t=a.soul.ify(t,i)}var r=c(t[m],s._);return void 0!==n&&n!==m&&(g(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},s.to=function(t,n,o){var e=(t||{})[n];return p(e)&&(e=d(e)),s.ify(o,n,s.is(t,n),e,a.soul(t))},function(){function u(t,n){m!==n&&s.ify(this.o,n,this.s)}s.map=function(i,r,a){var t=p(t=i||r)?t:null;return i=v(i=i||r)?i:null,t&&!i?(r=g(r)?r:s(),t[m]=t[m]||{},h(t,u,{o:t,s:r}),t):(a=a||p(r)?r:void 0,r=g(r)?r:s(),function(t,n,o,e){if(!i)return u.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),l(o,n)&&void 0===o[n]||u.call({o:o,s:r},t,n)})}}();var f=n.obj,c=f.as,l=f.has,p=f.is,h=f.map,d=f.copy,g=n.num.is,v=n.fn.is,m=a._;t.exports=s})(_,"./state"),_(function(t){var a=_("./type"),f=_("./val"),c=_("./node"),r={};!function(){function i(t,n){if(!t||n!==c.soul(t)||!c.is(t,this.fn,this.as))return!0;this.cb&&(o.n=t,o.as=this.as,this.cb.call(o.as,t,n,o))}function o(t){t&&c.is(o.n,t,o.as)}r.is=function(t,n,o,e){return!(!t||!l(t)||u(t))&&!s(t,i,{cb:n,fn:o,as:e})}}(),function(){function u(t,n){var o;return(o=function(t,n){var o,e=t.seen,i=e.length;for(;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}(t,n))?o:(n.env=t,n.soul=i,c.ify(n.obj,e,n)&&(n.link=n.link||f.link.ify(c.soul(n.node)),n.obj!==t.shell&&(t.graph[f.link.is(n.link)]=n.node)),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(c._===n&&h(t,f.link._))return o._;if(e=s(t,n,o,r,a)){if(n||(r.node=r.node||o||{},h(t,c._)&&c.soul(t)&&(r.node._=d(t._)),r.node=c.soul.ify(r.node,f.link.is(r.link)),r.link=r.link||f.link.ify(c.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),h(o,n))){if(void 0===(t=o[n]))return void p(o,n);if(!(e=s(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=u(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function i(t){var n=this,o=f.link.is(n.link),e=n.env.graph;n.link=n.link||f.link.ify(t),n.link[f.link._]=t,n.node&&n.node[c._]&&(n.node[c._][f.link._]=t),h(e,o)&&(e[t]=e[o],p(e,o))}function s(t,n,o,e,i){var r;return!!f.is(t)||(l(t)?1:(r=i.invalid)?s(t=r.call(i.as||{},t,n,o),n,o,e,i):(i.err="Invalid value at '"+e.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}r.ify=function(t,n,o){var e={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(e.link=f.link.ify(n.soul)),n.shell=(o||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,u(n,e),n.root=e.node,n.graph}}(),r.node=function(t){var n=c.soul(t);if(n)return o({},n,t)},function(){function i(t,n){var o,e;if(c._!==n)(o=f.link.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=r.to(this.graph,o,this.opt):this.obj[n]=t;else{if(u(t,f.link._))return;this.obj[n]=d(t)}}r.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},s(t[n],i,{obj:e,graph:t,opt:o}),e}}}();a.fn.is;var n=a.obj,l=n.is,p=n.del,h=n.has,u=n.empty,o=n.put,s=n.map,d=n.copy;t.exports=r})(_,"./graph"),_(function(t){_("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),o}}})(_,"./ask"),_(function(t){var r=_("./type");var a=r.time.is;t.exports=function(e){var i={s:{}};return e=e||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var o=i.s[t]||(i.s[t]={});return o.was=a(),n&&(o.pass=!0),i.to||(i.to=setTimeout(function(){var o=a();r.obj.map(i.s,function(t,n){t&&e.age>o-t.was||r.obj.del(i.s,n)}),i.to=null},e.age+9)),o},i}})(_,"./dup"),_(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=_("./type");n.obj.to(n,c),c.HAM=_("./HAM"),c.val=_("./val"),c.node=_("./node"),c.state=_("./state"),c.graph=_("./graph"),c.on=_("./onto"),c.ask=_("./ask"),c.dup=_("./dup"),function(){function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=u(9)),(n=i.dup).check(o)?e.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(o),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),e.out||(t.out=a,i.on("out",t)))}c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n}}(),function(){function i(t,n,o,e){var i=this,r=c.state.is(o,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=i.graph[e]||v,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[e]=c.state.to(o,n,i.put[e]),(i.diff||(i.diff={}))[e]=c.state.to(o,n,i.diff[e]),i.souls[e]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var o=this,e=o.$._,i=(e.next||v)[n];if(!i){if(!(e.opt||v).super)return void(o.souls[n]=!1);i=o.$.get(n)._}var r=o.map[n]={put:t,get:n,$:i.$},a={ctx:o,msg:r};o.async=!!e.tag.node,o.ack&&(r["@"]=o.ack),h(t,u,a),o.async&&(o.and||e.on("node",function(t){this.to.next(t),t===o.map[t.get]&&(o.souls[t.get]=!1,h(t.put,s,t),h(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),h(o.map,f,o)))}),o.and=!0,e.on("node",r))}function u(t,n){var o=this.ctx,e=o.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;e[r]=c.state.to(a,n,e[r]),o.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var o=this.put,e=this.$._;e.put=c.state.to(o,n,e.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}c.on.put=function(t,n){var o=n._,e={$:n,graph:o.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:o,stop:{}};if(c.graph.is(t.put,null,i,e)||(e.err="Error: Invalid graph!"),e.err)return o.on("in",{"@":t["#"],err:c.log(e.err)});h(e.put,r,e),e.async||h(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",p(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get,i=e[d],r=o.graph[i],a=e[g],u=(o.next||(o.next={}))[i];if(!r)return o.on("get",t);if(a){if("string"!=typeof a||!l(r,a))return o.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||v).ack,o.on("in",{"@":t["#"],how:"mem",put:r,$:n}),o.on("get",t)}}(),c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return s(t)||(t={}),s(n.opt)||(n.opt=t),r(o)&&(o=[o]),e(o)&&(o=h(o,function(t,n,o){(n={}).id=n.url=t,o(t,n)}),s(n.opt.peers)||(n.opt.peers={}),n.opt.peers=p(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},h(t,function t(n,o){!l(this,o)||i.is(n)||a.empty(n)?this[o]=n:n&&n.constructor!==Object&&!e(n)||h(n,t,this[o])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return f()+u(12)},this};var e=c.list.is,i=c.text,r=i.is,u=i.random,a=c.obj,s=a.is,l=a.has,p=a.to,h=a.map,f=(a.copy,c.state.lex),d=c.val.link._,g=".",v=(c.node._,c.val.link.is,{});b.debug=function(t,n){return b.debug.i&&t===b.debug.i&&b.debug.i++&&(b.log.apply(b,arguments)||n)},(c.log=function(){return!c.log.off&&b.log.apply(b,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,o){return(o=c.log.once)[t]=o[t]||0,o[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==o&&(o.exports=c)}catch(t){}t.exports=c})(_,"./root"),_(function(t){var u=_("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var o=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var e=0,i=t.length,r=o;e(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),o=0,e=n.root.now;u.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?u.to(i,n.root.mum):i,n.root.now=e},r),r.res&&r.res())}function n(t,n){if(t)return!0}function l(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||e)(function(){for(var t=a.path,n=u.ref,o=(u.opt,0),e=t.length;o .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(e.batch||1e3))return f();i||(i=setTimeout(f,e.wait||1))}),r.on("get",function(n){this.to.next(n);var o,e,i=n.get;function t(){if(i&&(o=i["#"])){var t=i["."];(e=s[o]||void 0)&&t&&(e=Gun.state.to(e,t)),r.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,o,e){s[e]=Gun.state.to(o,n,s[e])},f=function(t){var o;u=0,clearTimeout(i),i=!1;var n=a;a={},t&&(s=t);try{p.setItem(e.prefix,JSON.stringify(s))}catch(t){Gun.log(o=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),r.on("localStorage:error",{err:o,file:e.prefix,flush:s,retry:f})}(o||Gun.obj.empty(e.peers))&&Gun.obj.map(n,function(t,n){r.on("in",{"@":n,err:o,ok:0})})}}})}})(_,"./adapters/localStorage"),_(function(t){var d=_("../type");!function(){d.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<"])&&(o._.to=d.obj.map(r.split(","),f)),o.dam?void((r=c.hear[o.dam])&&r(o,n,s)):void s.on("in",o)}}else{try{o=JSON.parse(t)}catch(t){l.log("DAM JSON parse error",t)}if(!o)return;for(var a,u=0;a=o[u++];)c.hear(a,n)}}};var f=function(t,n,o){o(t,!0)};function h(n,o){try{var t=o.wire;o.say?o.say(n):t.send&&t.send(n),c.say.d+=n.length||0,++c.say.c}catch(t){(o.queue=o.queue||[]).push(n)}}c.hear.c=c.hear.d=0,function(){var u;function s(t){c.say(u,t)}function f(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return l.log("DAM JSON stringify error",t)}n&&h(n,t)}}c.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var o,e,i,r,a=t._||(t._=function(){});if((o=t["#"])||(o=t["#"]=d.text.random(9)),(e=t["##"])||void 0===t.put||(e=t["##"]=d.obj.hash(t.put)),!(r=a.raw)&&(r=a.raw=c.raw(t),e&&(i=t["@"])&&(p.track(i+e).it=t,i=(p.s[i]||!0).it))){if(e===i["##"])return!1;i["##"]=e}if(p.track(o).it=t,n||(n=(i=p.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via)),!n&&c.way)return c.way(t);if(!n||!n.id)return u=t,!!d.obj.is(n||l.peers)&&void d.obj.map(n||l.peers,s);if(!n.wire&&c.wire&&c.wire(n),o!==n.last){if(n.last=o,n===a.via)return!1;if((i=a.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=l.pack)return void n.batch.push(r);f(n)}n.batch=[],setTimeout(function(){f(n)},l.gap),h(r,n)}},c.say.c=c.say.d=0}(),function(){c.raw=function(t){if(!t)return"";var n,o=t._||{};if(n=o.raw)return n;if("string"==typeof t)return t;if(!t.dam){var e=0,i=[];d.obj.map(l.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++e)return!0}),1<"]=i.join())}var r=a(t);return o&&(o.raw=r),r};var a=JSON.stringify}(),c.hi=function(n){var t=n.wire||{};n.id?l.peers[n.url||n.id]=n:(t=n.id=n.id||d.text.random(9),c.say({dam:"?"},l.peers[t]=n)),n.met=n.met||+new Date,t.hied||s.on(t.hied="hi",n),t=n.queue,n.queue=[],d.obj.map(t,function(t){h(t,n)})},c.bye=function(t){s.on("bye",t);var n=+new Date;n-=t.met||n,c.bye.time=((c.bye.time||n)+n)/2},c.hear["!"]=function(t,n){l.log("Error:",t.err)},c.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):c.say({dam:"?",pid:l.pid,"@":t["#"]},n)},s.on("create",function(t){t.opt.pid=t.opt.pid||d.text.random(9),this.to.next(t),t.on("out",c.say)}),s.on("bye",function(t,n){t=l.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),d.obj.del(l.peers,t.id),t.wire=null});var i={};return s.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},l.lack||9e3))}),s.on("hi",function(o,e){this.to.next(o),(e=o.url)&&i[e]&&(delete i[e],d.obj.map(s.next,function(t,n){(e={})[n]=s.graph[n],c.say({"##":d.obj.hash(e),get:{"#":n}},o)}))}),c}}catch(t){}})(_,"./adapters/mesh"),_(function(t){var f=_("../index");f.Mesh=_("./mesh"),f.on("opt",function(t){this.to.next(t);var e=t.opt;if(!t.once&&!1!==e.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=e.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(o){e.WebSocket=o;var i=e.mesh=e.mesh||f.Mesh(t);i.wire||e.wire;i.wire=e.wire=u;var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return o&&o(n);var t=n.url.replace("http","ws"),o=n.wire=new e.WebSocket(t);return o.onclose=function(){e.mesh.bye(n),s(n)},o.onerror=function(t){s(n)},o.onopen=function(){e.mesh.hi(n)},o.onmessage=function(t){t&&e.mesh.hear(t.data||t,n)},o}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||e.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})(_,"./adapters/websocket")}(); \ No newline at end of file +!function(){var t;"undefined"!=typeof window&&(t=window),"undefined"!=typeof global&&(t=global);var j=(t=t||{}).console||{log:function(){}};function $(o,t){return t?require(o):o.slice?$[e(o)]:function(t,n){o(t={exports:{}}),$[e(n)]=t.exports};function e(t){return t.split("/").slice(-1).toString().replace(".js","")}}if("undefined"!=typeof module)var o=module;$(function(t){var n,c,l={};function o(t,n){v(this,n)&&void 0!==this[n]||(this[n]=t)}function e(t,n){var o=this.n;if(!o||!(n===o||g(o)&&v(o,n)))return!!n||void 0}function p(t,n){2!==arguments.length?(p.r=p.r||[]).push(t):(p.r=p.r||{})[t]=n}l.fn={is:function(t){return!!t&&"function"==typeof t}},l.bi={is:function(t){return t instanceof Boolean||"boolean"==typeof t}},l.num={is:function(t){return!d(t)&&(0<=t-parseFloat(t)+1||1/0===t||-1/0===t)}},l.text={is:function(t){return"string"==typeof t}},l.text.ify=function(t){return l.text.is(t)?t:"undefined"!=typeof JSON?JSON.stringify(t):t&&t.toString?t.toString():t},l.text.random=function(t,n){var o="";for(t=t||24,n=n||"0123456789ABCDEFGHIJKLMNOPQRSTUVWXZabcdefghijklmnopqrstuvwxyz";0"]||n["<"])||e===n["="]&&(o=n["*"]||n[">"]||n["<"],t.slice(0,(o||"").length)===o||e===n["*"]&&(e!==n[">"]&&e!==n["<"]?t>=n[">"]&&t<=n["<"]:e!==n[">"]&&t>=n[">"]||e!==n["<"]&&t<=n["<"])))},l.list={is:function(t){return t instanceof Array}},l.list.slit=Array.prototype.slice,l.list.sort=function(o){return function(t,n){return t&&n?(t=t[o])<(n=n[o])?-1:n",u.drift=0,u.is=function(t,n,o){var e=n&&t&&t[k]&&t[k][u._]||o;if(e)return v(e=e[n])?e:-1/0},u.lex=function(){return u().toString(36).replace(".","")},u.ify=function(t,n,o,e,i){if(!t||!t[k]){if(!i)return;t=a.soul.ify(t,i)}var r=l(t[k],u._);return void 0!==n&&n!==k&&(v(o)&&(r[n]=o),void 0!==e&&(t[n]=e)),t},u.to=function(t,n,o){var e=(t||{})[n];return h(e)&&(e=g(e)),u.ify(o,n,u.is(t,n),e,a.soul(t))},u.map=function(i,r,a){var t=h(t=i||r)?t:null;return i=m(i=i||r)?i:null,t&&!i?(r=v(r)?r:u(),t[k]=t[k]||{},d(t,f,{o:t,s:r}),t):(a=a||h(r)?r:void 0,r=v(r)?r:u(),function(t,n,o,e){if(!i)return f.call({o:o,s:r},t,n),t;i.call(a||this||{},t,n,o,e),p(o,n)&&void 0===o[n]||f.call({o:o,s:r},t,n)})};var c=n.obj,l=c.as,p=c.has,h=c.is,d=c.map,g=c.copy,v=n.num.is,m=n.fn.is,k=a._;t.exports=u})($,"./state"),$(function(t){var a=$("./type"),u=$("./val"),s=$("./node"),i={};function r(t,n){if(!t||n!==s.soul(t)||!s.is(t,this.fn,this.as))return!0;this.cb&&(o.n=t,o.as=this.as,this.cb.call(o.as,t,n,o))}function o(t){t&&s.is(o.n,t,o.as)}function f(t,n){var o;return(o=function(t,n){var o,e=t.seen,i=e.length;for(;i--;)if(o=e[i],n.obj===o.obj)return o;e.push(n)}(t,n))?o:(n.env=t,n.soul=c,s.ify(n.obj,e,n)&&(n.link=n.link||u.link.ify(s.soul(n.node)),n.obj!==t.shell&&(t.graph[u.link.is(n.link)]=n.node)),n)}function e(t,n,o){var e,i,r=this,a=r.env;if(s._===n&&g(t,u.link._))return o._;if(e=l(t,n,o,r,a)){if(n||(r.node=r.node||o||{},g(t,s._)&&s.soul(t)&&(r.node._=b(t._)),r.node=s.soul.ify(r.node,u.link.is(r.link)),r.link=r.link||u.link.ify(s.soul(r.node))),(i=a.map)&&(i.call(a.as||{},t,n,o,r),g(o,n))){if(void 0===(t=o[n]))return void d(o,n);if(!(e=l(t,n,o,r,a)))return}if(!n)return r.node;if(!0===e)return t;if((i=f(a,{obj:t,path:r.path.concat(n)})).node)return i.link}}function c(t){var n=this,o=u.link.is(n.link),e=n.env.graph;n.link=n.link||u.link.ify(t),n.link[u.link._]=t,n.node&&n.node[s._]&&(n.node[s._][u.link._]=t),g(e,o)&&(e[t]=e[o],d(e,o))}function l(t,n,o,e,i){var r;return!!u.is(t)||(h(t)?1:(r=i.invalid)?l(t=r.call(i.as||{},t,n,o),n,o,e,i):(i.err="Invalid value at '"+e.path.concat(n).join(".")+"'!",void(a.list.is(t)&&(i.err+=" Use `.set(item)` instead of an Array."))))}function p(t,n){var o,e;if(s._!==n)(o=u.link.is(t))?(e=this.opt.seen[o])?this.obj[n]=e:this.obj[n]=this.opt.seen[o]=i.to(this.graph,o,this.opt):this.obj[n]=t;else{if(v(t,u.link._))return;this.obj[n]=b(t)}}i.is=function(t,n,o,e){return!(!t||!h(t)||v(t)||k(t,r,{cb:n,fn:o,as:e}))},i.ify=function(t,n,o){var e={path:[],obj:t};return n?"string"==typeof n?n={soul:n}:n instanceof Function&&(n.map=n):n={},n.soul&&(e.link=u.link.ify(n.soul)),n.shell=(o||{}).shell,n.graph=n.graph||{},n.seen=n.seen||[],n.as=n.as||o,f(n,e),n.root=e.node,n.graph},i.node=function(t){var n=s.soul(t);if(n)return m({},n,t)},i.to=function(t,n,o){if(t){var e={};return o=o||{seen:{}},k(t[n],p,{obj:e,graph:t,opt:o}),e}};a.fn.is;var n=a.obj,h=n.is,d=n.del,g=n.has,v=n.empty,m=n.put,k=n.map,b=n.copy;t.exports=i})($,"./graph"),$(function(t){$("./onto"),t.exports=function(t,n){if(this.on){if(!(t instanceof Function)){if(!t||!n)return;var o=t["#"]||t,e=(this.tag||empty)[o];if(!e)return;return e=this.on(o,n),clearTimeout(e.err),!0}o=n&&n["#"]||Math.random().toString(36).slice(2);if(!t)return o;var i=this.on(o,t,n);return i.err=i.err||setTimeout(function(){i.next({err:"Error: No ACK received yet.",lack:!0}),i.off()},(this.opt||{}).lack||9e3),o}}})($,"./ask"),$(function(t){var r=$("./type");var a=r.time.is;t.exports=function(e){var i={s:{}};return e=e||{max:1e3,age:9e3},i.check=function(t){var n;return!!(n=i.s[t])&&(n.pass?n.pass=!1:i.track(t))},i.track=function(t,n){var o=i.s[t]||(i.s[t]={});return o.was=a(),n&&(o.pass=!0),i.to||(i.to=setTimeout(function(){var o=a();r.obj.map(i.s,function(t,n){t&&e.age>o-t.was||r.obj.del(i.s,n)}),i.to=null},e.age+9)),o},i}})($,"./dup"),$(function(t){function c(t){return t instanceof c?(this._={gun:this,$:this}).$:this instanceof c?c.create(this._={gun:this,$:this,opt:t}):new c(t)}c.is=function(t){return t instanceof c||t&&t._&&t===t._.$||!1},c.version=.9,(c.chain=c.prototype).toJSON=function(){};var n=$("./type");function a(t){var n,o,e=this.as,i=e.at||e,r=i.$;(o=t["#"])||(o=t["#"]=h(9)),(n=i.dup).check(o)?e.out===t.out&&(t.out=void 0,this.to.next(t)):(n.track(o),i.ask(t["@"],t)||(t.get&&c.on.get(t,r),t.put&&c.on.put(t,r)),this.to.next(t),e.out||(t.out=a,i.on("out",t)))}function i(t,n,o,e){var i=this,r=c.state.is(o,n);if(!r)return i.err="Error: No state on '"+n+"' in node '"+e+"'!";var a=i.graph[e]||x,u=c.state.is(a,n,!0),s=a[n],f=c.HAM(i.machine,r,u,t,s);f.incoming?(i.put[e]=c.state.to(o,n,i.put[e]),(i.diff||(i.diff={}))[e]=c.state.to(o,n,i.diff[e]),i.souls[e]=!0):f.defer&&(i.defer=r<(i.defer||1/0)?r:i.defer)}function r(t,n){var o=this,e=o.$._,i=(e.next||x)[n];if(!i){if(!(e.opt||x).super)return void(o.souls[n]=!1);i=o.$.get(n)._}var r=o.map[n]={put:t,get:n,$:i.$},a={ctx:o,msg:r};o.async=!!e.tag.node,o.ack&&(r["@"]=o.ack),k(t,u,a),o.async&&(o.and||e.on("node",function(t){this.to.next(t),t===o.map[t.get]&&(o.souls[t.get]=!1,k(t.put,s,t),k(o.souls,function(t){if(t)return t})||o.c||(o.c=1,this.off(),k(o.map,f,o)))}),o.and=!0,e.on("node",r))}function u(t,n){var o=this.ctx,e=o.graph,i=this.msg,r=i.get,a=i.put,u=i.$._;e[r]=c.state.to(a,n,e[r]),o.async||(u.put=c.state.to(a,n,u.put))}function s(t,n){var o=this.put,e=this.$._;e.put=c.state.to(o,n,e.put)}function f(t,n){t.$&&(this.cat.stop=this.stop,t.$._.on("in",t),this.cat.stop=null)}n.obj.to(n,c),c.HAM=$("./HAM"),c.val=$("./val"),c.node=$("./node"),c.state=$("./state"),c.graph=$("./graph"),c.on=$("./onto"),c.ask=$("./ask"),c.dup=$("./dup"),c.create=function(t){t.root=t.root||t,t.graph=t.graph||{},t.on=t.on||c.on,t.ask=t.ask||c.ask,t.dup=t.dup||c.dup();var n=t.$.opt(t.opt);return t.once||(t.on("in",a,t),t.on("out",a,{at:t,out:a}),c.on("create",t),t.on("create",t)),t.once=1,n},c.on.put=function(t,n){var o=n._,e={$:n,graph:o.graph,put:{},map:{},souls:{},machine:c.state(),ack:t["@"],cat:o,stop:{}};if(c.graph.is(t.put,null,i,e)||(e.err="Error: Invalid graph!"),e.err)return o.on("in",{"@":t["#"],err:c.log(e.err)});k(e.put,r,e),e.async||k(e.map,f,e),void 0!==e.defer&&setTimeout(function(){c.on.put(t,n)},e.defer-e.machine),e.diff&&o.on("put",m(t,{put:e.diff}))},c.on.get=function(t,n){var o=n._,e=t.get,i=e[y],r=o.graph[i],a=e[_],u=(o.next||(o.next={}))[i];if(!r)return o.on("get",t);if(a){if("string"!=typeof a||!v(r,a))return o.on("get",t);r=c.state.to(r,a)}else r=c.obj.copy(r);r=c.graph.node(r),(u||x).ack,o.on("in",{"@":t["#"],how:"mem",put:r,$:n}),o.on("get",t)},c.chain.opt=function(t){t=t||{};var n=this._,o=t.peers||t;return g(t)||(t={}),g(n.opt)||(n.opt=t),p(o)&&(o=[o]),e(o)&&(o=k(o,function(t,n,o){(n={}).id=n.url=t,o(t,n)}),g(n.opt.peers)||(n.opt.peers={}),n.opt.peers=m(o,n.opt.peers)),n.opt.peers=n.opt.peers||{},k(t,function t(n,o){!v(this,o)||l.is(n)||d.empty(n)?this[o]=n:n&&n.constructor!==Object&&!e(n)||k(n,t,this[o])},n.opt),c.on("opt",n),n.opt.uuid=n.opt.uuid||function(){return b()+h(12)},this};var e=c.list.is,l=c.text,p=l.is,h=l.random,d=c.obj,g=d.is,v=d.has,m=d.to,k=d.map,b=(d.copy,c.state.lex),y=c.val.link._,_=".",x=(c.node._,c.val.link.is,{});j.only=function(t,n){return j.only.i&&t===j.only.i&&j.only.i++&&(j.log.apply(j,arguments)||n)},(c.log=function(){return c.log.off||j.log.apply(j,arguments),[].slice.call(arguments).join(" ")}).once=function(t,n,o){return(o=c.log.once)[t]=o[t]||0,o[t]++||c.log(n)},c.log.once("welcome","Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!"),"undefined"!=typeof window&&((window.GUN=window.Gun=c).window=window);try{void 0!==o&&(o.exports=c)}catch(t){}t.exports=c})($,"./root"),$(function(t){var u=$("./root");u.chain.back=function(t,n){if(-1===(t=t||1)||1/0===t)return this._.root.$;if(1===t)return(this._.back||this._).$;var o=this._;if("string"==typeof t&&(t=t.split(".")),t instanceof Array){for(var e=0,i=t.length,r=o;e(r.acks||0)&&this.off(),r.ack&&r.ack(t,this)},r.opt),o=0,e=n.root.now;h.del(n.root,"now");var i=n.root.mum;n.root.mum={},r.ref._.on("out",{$:r.ref,put:r.out=r.env.graph,opt:r.opt,"#":t}),n.root.mum=i?h.to(i,n.root.mum):i,n.root.now=e},r),r.res&&r.res())}function n(t,n){if(t)return!0}function c(r,t,n,a){var u=this,s=f.is(r);!t&&a.path.length&&(u.res||e)(function(){for(var t=a.path,n=u.ref,o=(u.opt,0),e=t.length;o .once, apologies unexpected."),this.once(t,n)},f.chain.once=function(t,n){var o=this,e=o._,i=e.put;if(0=(e.batch||1e3))return f();i=i||setTimeout(f,e.wait||1)}),a.on("get",function(n){this.to.next(n);var o,e,i,r=n.get;function t(){if(r&&(o=r["#"])){var t=r["."];(e=s[o]||i)&&t&&(e=Gun.state.to(e,t)),a.on("in",{"@":n["#"],put:Gun.graph.node(e),how:"lS",lS:n.$})}}Gun.debug?setTimeout(t,1):t()});var n=function(t,n,o,e){s[e]=Gun.state.to(o,n,s[e])},f=function(t){var o;u=0,clearTimeout(i),i=!1;var n=r;r={},t&&(s=t);try{p.setItem(e.prefix,JSON.stringify(s))}catch(t){Gun.log(o=(t||"localStorage failure")+" Consider using GUN's IndexedDB plugin for RAD for more storage space, https://gun.eco/docs/RAD#install"),a.on("localStorage:error",{err:o,file:e.prefix,flush:s,retry:f})}(o||Gun.obj.empty(e.peers))&&Gun.obj.map(n,function(t,n){a.on("in",{"@":n,err:o,ok:0})})}}})}})($,"./adapters/localStorage"),$(function(t){var v=$("../type");!function(){v.text.hash=function(t){if("string"!=typeof t)return{err:1};var n=0;if(!t.length)return n;for(var o=0,e=t.length;o<"])&&(o._.to=v.obj.map(r.split(","),p)),o.dam?void((r=f.hear[o.dam])&&r(o,n,s)):void s.on("in",o)}}else{try{o=JSON.parse(t)}catch(t){c.log("DAM JSON parse error",t)}if(!o)return;for(var a,u=0;a=o[u++];)f.hear(a,n)}}};var u,p=function(t,n,o){o(t,!0)};function h(t){f.say(u,t)}function d(t){var n=t.batch;if(t.batch=t.tail=null,n&&n.length){try{n=1===n.length?n[0]:JSON.stringify(n)}catch(t){return c.log("DAM JSON stringify error",t)}n&&g(n,t)}}function g(n,o){try{var t=o.wire;o.say?o.say(n):t.send&&t.send(n),f.say.d+=n.length||0,++f.say.c}catch(t){(o.queue=o.queue||[]).push(n)}}f.hear.c=f.hear.d=0,f.say=function(t,n){if(this.to&&this.to.next(t),!t)return!1;var o,e,i,r,a=t._||(t._=function(){});if((o=t["#"])||(o=t["#"]=v.text.random(9)),(e=t["##"])||void 0===t.put||(e=t["##"]=v.obj.hash(t.put)),!(r=a.raw)&&(r=a.raw=f.raw(t),e&&(i=t["@"])&&(l.track(i+e).it=t,i=(l.s[i]||!0).it))){if(e===i["##"])return!1;i["##"]=e}if(l.track(o).it=t,!(n=n||(i=l.s[t["@"]])&&(i=i.it)&&(i=i._)&&(i=i.via))&&f.way)return f.way(t);if(!n||!n.id)return u=t,!!v.obj.is(n||c.peers)&&void v.obj.map(n||c.peers,h);if(!n.wire&&f.wire&&f.wire(n),o!==n.last){if(n.last=o,n===a.via)return!1;if((i=a.to)&&(i[n.url]||i[n.pid]||i[n.id]))return!1;if(n.batch){if(n.tail=(i=n.tail||0)+r.length,n.tail<=c.pack)return void n.batch.push(r);d(n)}n.batch=[],setTimeout(function(){d(n)},c.gap),g(r,n)}},f.say.c=f.say.d=0,function(){f.raw=function(t){if(!t)return"";var n,o=t._||{};if(n=o.raw)return n;if("string"==typeof t)return t;if(!t.dam){var e=0,i=[];v.obj.map(c.peers,function(t){if(i.push(t.url||t.pid||t.id),9<++e)return!0}),1<"]=i.join())}var r=a(t);return o&&(o.raw=r),r};var a=JSON.stringify}(),f.hi=function(n){var t=n.wire||{};n.id?c.peers[n.url||n.id]=n:(t=n.id=n.id||v.text.random(9),f.say({dam:"?"},c.peers[t]=n)),n.met=n.met||+new Date,t.hied||s.on(t.hied="hi",n),t=n.queue,n.queue=[],v.obj.map(t,function(t){g(t,n)})},f.bye=function(t){s.on("bye",t);var n=+new Date;n-=t.met||n,f.bye.time=((f.bye.time||n)+n)/2},f.hear["!"]=function(t,n){c.log("Error:",t.err)},f.hear["?"]=function(t,n){t.pid?n.pid||(n.pid=t.pid):f.say({dam:"?",pid:c.pid,"@":t["#"]},n)},s.on("create",function(t){t.opt.pid=t.opt.pid||v.text.random(9),this.to.next(t),t.on("out",f.say)}),s.on("bye",function(t,n){t=c.peers[t.id||t]||t,this.to.next(t),t.bye?t.bye():(n=t.wire)&&n.close&&n.close(),v.obj.del(c.peers,t.id),t.wire=null});var i={};return s.on("bye",function(t,n){this.to.next(t),(n=t.url)&&(i[n]=!0,setTimeout(function(){delete i[n]},c.lack||9e3))}),s.on("hi",function(o,e){this.to.next(o),(e=o.url)&&i[e]&&(delete i[e],v.obj.map(s.next,function(t,n){(e={})[n]=s.graph[n],f.say({"##":v.obj.hash(e),get:{"#":n}},o)}))}),f}}catch(t){}})($,"./adapters/mesh"),$(function(t){var f=$("../index");f.Mesh=$("./mesh"),f.on("opt",function(t){this.to.next(t);var e=t.opt;if(!t.once&&!1!==e.WebSocket){var n;"undefined"!=typeof window&&(n=window),"undefined"!=typeof global&&(n=global),n=n||{};var o=e.WebSocket||n.WebSocket||n.webkitWebSocket||n.mozWebSocket;if(o){e.WebSocket=o;var i=e.mesh=e.mesh||f.Mesh(t);i.wire||e.wire;i.wire=e.wire=u;var r=2e3,a="undefined"!=typeof document&&document}}function u(n){try{if(!n||!n.url)return o&&o(n);var t=n.url.replace("http","ws"),o=n.wire=new e.WebSocket(t);return o.onclose=function(){e.mesh.bye(n),s(n)},o.onerror=function(t){s(n)},o.onopen=function(){e.mesh.hi(n)},o.onmessage=function(t){t&&e.mesh.hear(t.data||t,n)},o}catch(t){}}function s(n){clearTimeout(n.defer),a&&n.retry<=0||(n.retry=(n.retry||e.retry||60)-1,n.defer=setTimeout(function t(){if(a&&a.hidden)return setTimeout(t,r);u(n)},r))}})})($,"./adapters/websocket")}(); \ No newline at end of file diff --git a/sea/array.js b/sea/array.js index d10c983c..e6fa5765 100644 --- a/sea/array.js +++ b/sea/array.js @@ -1,6 +1,5 @@ - function btoa(b) { - return new Buffer(b).toString('base64'); - }; + + require('./base64'); // This is Array extended to have .toString(['utf8'|'hex'|'base64']) function SeaArray() {} Object.assign(SeaArray, { from: Array.from }) diff --git a/sea/base64.js b/sea/base64.js new file mode 100644 index 00000000..5a87f29e --- /dev/null +++ b/sea/base64.js @@ -0,0 +1,7 @@ + + if(typeof global !== "undefined"){ + var g = global; + g.btoa = function (data) { return Buffer.from(data, "binary").toString("base64"); }; + g.atob = function (data) { return Buffer.from(data, "base64").toString("binary"); }; + } + \ No newline at end of file diff --git a/sea/buffer.js b/sea/buffer.js index 37f753b4..77915f1e 100644 --- a/sea/buffer.js +++ b/sea/buffer.js @@ -1,6 +1,5 @@ - function atob(a) { - return new Buffer(a, 'base64').toString('binary'); - }; + + require('./base64'); // This is Buffer implementation used in SEA. Functionality is mostly // compatible with NodeJS 'safe-buffer' and is used for encoding conversions // between binary and 'hex' | 'utf8' | 'base64' diff --git a/sea/secret.js b/sea/secret.js index b52a6fc6..4a1c63ac 100644 --- a/sea/secret.js +++ b/sea/secret.js @@ -13,7 +13,7 @@ var epriv = pair.epriv; var ecdhSubtle = shim.ossl || shim.subtle; var pubKeyData = keysToEcdhJwk(pub); - var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },S.ecdh); + var props = Object.assign({ public: await ecdhSubtle.importKey(...pubKeyData, true, []) },S.ecdh); // Thanks to @sirpy ! var privKeyData = keysToEcdhJwk(epub, epriv); var derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey']).then(async (privKey) => { // privateKey scope doesn't leak out from here! @@ -47,4 +47,4 @@ } module.exports = SEA.secret; - + \ No newline at end of file diff --git a/sea/shim.js b/sea/shim.js index 21d94355..22ca351d 100644 --- a/sea/shim.js +++ b/sea/shim.js @@ -22,7 +22,7 @@ random: (len) => Buffer.from(crypto.randomBytes(len)) }); //try{ - const { Crypto: WebCrypto } = USE('@peculiar/webcrypto', 1); + const { Crypto: WebCrypto } = require('@peculiar/webcrypto', 1); api.ossl = api.subtle = new WebCrypto({directory: 'ossl'}).subtle // ECDH //}catch(e){ //console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed."); diff --git a/src/adapters/localStorage.js b/src/adapters/localStorage.js index 5cf6b718..1d0e60cf 100644 --- a/src/adapters/localStorage.js +++ b/src/adapters/localStorage.js @@ -17,7 +17,7 @@ Gun.on('create', function(root){ // See the next 'opt' code below for actual saving of data. var ev = this.to, opt = root.opt; if(root.once){ return ev.next(root) } - //if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! + if(false === opt.localStorage){ return ev.next(root) } // we want offline resynce queue regardless! // actually, this doesn't help, per @go1dfish 's observation. Disabling for now, will need better solution later. opt.prefix = opt.file || 'gun/'; var gap = Gun.obj.ify(store.getItem('gap/'+opt.prefix)) || {}; var empty = Gun.obj.empty, id, to, go; diff --git a/src/get.js b/src/get.js index 3725896b..e29e62db 100644 --- a/src/get.js +++ b/src/get.js @@ -11,7 +11,7 @@ Gun.chain.get = function(key, cb, as){ gun = gun.$; } else if(key instanceof Function){ - if(true === cb){ return soul(this, key, cb, as) } + if(true === cb){ return soul(this, key, cb, as), this } gun = this; var at = gun._, root = at.root, tmp = root.now, ev; as = cb || {}; @@ -68,15 +68,22 @@ function cache(key, back){ } function soul(gun, cb, opt, as){ var cat = gun._, acks = 0, tmp; - if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat), gun } - gun.get(function(msg, ev){ + if(tmp = cat.soul || cat.link || cat.dub){ return cb(tmp, as, cat) } + if(cat.jam){ return cat.jam.push([cb, as]) } + cat.jam = [[cb,as]]; + gun.get(function(msg, eve){ if(u === msg.put && (tmp = Object.keys(cat.root.opt.peers).length) && ++acks < tmp){ return; } - ev.rid(msg); + eve.rid(msg); var at = ((at = msg.$) && at._) || {}; - tmp = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put) || at.dub; - cb(tmp, as, msg, ev); + tmp = cat.jam; Gun.obj.del(cat, 'jam'); + Gun.obj.map(tmp, function(as, cb){ + cb = as[0]; as = as[1]; + if(!cb){ return } + var id = at.link || at.soul || rel.is(msg.put) || node_soul(msg.put) || at.dub; + cb(id, as, msg, eve); + }); }, {out: {get: {'.':true}}}); return gun; } diff --git a/src/put.js b/src/put.js index 4e23d8b4..b74ee08c 100644 --- a/src/put.js +++ b/src/put.js @@ -3,9 +3,9 @@ var Gun = require('./root'); Gun.chain.put = function(data, cb, as){ // #soul.has=value>state // ~who#where.where=what>when@was - // TODO: BUG! Put probably cannot handle plural chains! + // TODO: BUG! Put probably cannot handle plural chains! `!as` is quickfix test. var gun = this, at = (gun._), root = at.root.$, ctx = root._, M = 100, tmp; - if(!ctx.puta){ if(tmp = ctx.puts){ if(tmp > M){ // without this, when synchronous, writes to a 'not found' pile up, when 'not found' resolves it recursively calls `put` which incrementally resolves each write. Stack overflow limits can be as low as 10K, so this limit is hardcoded to 1% of 10K. + /*if(!ctx.puta && !as){ if(tmp = ctx.puts){ if(tmp > M){ // without this, when synchronous, writes to a 'not found' pile up, when 'not found' resolves it recursively calls `put` which incrementally resolves each write. Stack overflow limits can be as low as 10K, so this limit is hardcoded to 1% of 10K. (ctx.stack || (ctx.stack = [])).push([gun, data, cb, as]); if(ctx.puto){ return } ctx.puto = setTimeout(function drain(){ @@ -15,7 +15,7 @@ Gun.chain.put = function(data, cb, as){ ctx.stack = ctx.puts = ctx.puto = null; }, 0); return gun; - } ++ctx.puts } else { ctx.puts = 1 } } + } ++ctx.puts } else { ctx.puts = 1 } }*/ as = as || {}; as.data = data; as.via = as.$ = as.via || as.$ || gun; @@ -138,6 +138,7 @@ function map(v,k,n, at){ var as = this; ref = ref.get(path[i]); } if(is){ ref = v } + //if(as.not){ (ref._).dub = Gun.text.random() } // This might optimize stuff? Maybe not needed anymore. Make sure it doesn't introduce bugs. var id = (ref._).dub; if(id || (id = Gun.node.soul(at.obj))){ ref.back(-1).get(id); @@ -198,6 +199,7 @@ function any(soul, as, msg, eve){ if(at.link || at.soul){ return at.link || at.soul } as.data = obj_put({}, at.get, as.data); }); + as.not = true; // maybe consider this? } tmp = tmp || at.soul || at.link || at.dub;// || at.get; at = tmp? (at.root.$.get(tmp)._) : at; diff --git a/src/root.js b/src/root.js index 94a2f244..187a3bdc 100644 --- a/src/root.js +++ b/src/root.js @@ -209,7 +209,7 @@ var obj = Gun.obj, obj_is = obj.is, obj_has = obj.has, obj_to = obj.to, obj_map var state_lex = Gun.state.lex, _soul = Gun.val.link._, _has = '.', node_ = Gun.node._, rel_is = Gun.val.link.is; var empty = {}, u; -console.debug = function(i, s){ return (console.debug.i && i === console.debug.i && console.debug.i++) && (console.log.apply(console, arguments) || s) }; +console.only = function(i, s){ return (console.only.i && i === console.only.i && console.only.i++) && (console.log.apply(console, arguments) || s) }; Gun.log = function(){ return (!Gun.log.off && console.log.apply(console, arguments)), [].slice.call(arguments).join(' ') } Gun.log.once = function(w,s,o){ return (o = Gun.log.once)[w] = o[w] || 0, o[w]++ || Gun.log(s) } From f4526238f3cdae6453f25a018ce94302f4a665ba Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Sep 2019 00:27:39 -0700 Subject: [PATCH 18/19] add more stats --- examples/stats.html | 16 ++++++++++++++++ gun.js | 2 ++ lib/stats.js | 3 ++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/stats.html b/examples/stats.html index e8ee7944..b6dfe27d 100644 --- a/examples/stats.html +++ b/examples/stats.html @@ -45,6 +45,10 @@
+
+
+
+
@@ -130,6 +134,18 @@ stats.show = async function(data){ //$.getJSON(url.value||(location.origin+'/gun }}); }catch(e){} + try{ + stats.daml = Object.values(data.dam['in'].long).map(function(n){ return n }); + new Chartist.Line('.ct-daml', { + // A labels array that can contain any sort of values + //labels: ['-1min', '-45s', '-30s', '-15s', '0'], + // Our series array that contains series objects or in this case series data arrays + series: [stats.daml] + }, {fullWidth: true, axisY: { + labelInterpolationFnc: function(v) { return v+'ms' } + }}); + }catch(e){} + new Chartist.Line('.ct-cpu', { // A labels array that can contain any sort of values labels: ['-15min', '-5min', '1min'], diff --git a/gun.js b/gun.js index 851a01f3..a06a6c75 100644 --- a/gun.js +++ b/gun.js @@ -1973,9 +1973,11 @@ try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } var i = 0, m; + var S = +new Date; // STATS! while(m = msg[i++]){ mesh.hear(m, peer); } + (mesh.hear.long || (mesh.hear.long = [])).push(+new Date - S); return; } if('{' === tmp || (Type.obj.is(raw) && (msg = raw))){ diff --git a/lib/stats.js b/lib/stats.js index 2e7a943a..5039f05d 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -41,9 +41,10 @@ Gun.on('opt', function(root){ stats.node.count = Object.keys(root.graph||{}).length; var dam = root.opt.mesh; if(dam){ - stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d}, 'out': {count: dam.say.c, done: dam.say.d}}; + stats.dam = {'in': {count: dam.hear.c, done: dam.hear.d, long: dam.hear.long}, 'out': {count: dam.say.c, done: dam.say.d}}; dam.hear.c = dam.hear.d = dam.say.c = dam.say.d = 0; // reset stats.peers.time = dam.bye.time || 0; + dam.hear.long = []; } var rad = root.opt.store; rad = rad && rad.stats; if(rad){ From 14f6ba098addb10acb0969b09fdbba942d010d59 Mon Sep 17 00:00:00 2001 From: Mark Nadal Date: Tue, 17 Sep 2019 08:26:42 -0700 Subject: [PATCH 19/19] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c584a776..2ad4399d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Famark%2Fgun.svg?size=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Famark%2Fgun?ref=badge_shield) [![Gitter](https://img.shields.io/gitter/room/amark/gun.js.svg)](https://gitter.im/amark/gun) -**GUN** is an _ecosystem_ of tools that let you build tomorrow's dApps, today. +**GUN** is an _ecosystem_ of tools that let you build [community run](https://www.nbcnews.com/tech/tech-news/these-technologists-think-internet-broken-so-they-re-building-another-n1030136) and encrypted applications. + +Currently, [Internet Archive](https://news.ycombinator.com/item?id=17685682) and HackerNoon run GUN in production. Decentralized alternatives to [Reddit](https://notabug.io/t/whatever/comments/36588a16b9008da4e3f15663c2225e949eca4a15/gpu-bot-test), [YouTube](https://d.tube/), [Wikipedia](https://news.ycombinator.com/item?id=17685682), etc. are already pushing terabytes of daily P2P traffic on GUN. We are a [friendly community](https://gitter.im/amark/gun) creating a free fun future for freedom: