Merge branch 'master' into dev

This commit is contained in:
Mark Nadal 2018-12-13 17:20:05 -08:00
commit 286a43087e
19 changed files with 184 additions and 123 deletions

View File

@ -112,7 +112,8 @@ Thanks to:<br/>
<a href="http://github.com/ctrlplusb">Sean Matheson</a>,
<a href="http://github.com/alanmimms">Alan Mimms</a>,
<a href="https://github.com/dfreire">Dário Freire</a>,
<a href="http://github.com/velua">John Williamson</a>
<a href="http://github.com/velua">John Williamson</a>,
<a href="http://github.com/finwo">Robin Bron</a>
</p>
- Join others in sponsoring code: https://www.patreon.com/gunDB !

4
gun.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,7 @@ function Mem(opt){
cb(null, tmp);
}, 1);
};
store.list = function(cb, match){
store.list = function(cb, match){ // supporting this is no longer needed! Optional.
setTimeout(function(){
Gun.obj.map(Object.keys(storage), cb) || cb();
}, 1);
@ -85,4 +85,4 @@ function Mem(opt){
return store;
}
module.exports = Store;//Gun.TESTING? Mem : Store;
module.exports = Store;//Gun.TESTING? Mem : Store;

View File

@ -1,6 +1,6 @@
{
"name": "gun",
"version": "0.9.99999",
"version": "0.9.999992",
"description": "A realtime, decentralized, offline-first, graph data synchronization engine.",
"main": "index.js",
"browser": "gun.min.js",

108
sea.js
View File

@ -282,7 +282,7 @@
}
salt = salt || shim.random(9);
if('SHA-256' === opt.name){
var rsha = shim.Buffer.from(await sha(data), 'binary').toString('utf8')
var rsha = shim.Buffer.from(await sha(data), 'binary').toString(opt.encode || 'base64')
if(cb){ try{ cb(rsha) }catch(e){console.log(e)} }
return rsha;
}
@ -296,7 +296,7 @@
hash: opt.hash || S.pbkdf2.hash,
}, key, opt.length || (S.pbkdf2.ks * 8))
data = shim.random(data.length) // Erase data in case of passphrase
const r = shim.Buffer.from(result, 'binary').toString('utf8')
const r = shim.Buffer.from(result, 'binary').toString(opt.encode || 'base64')
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {
@ -392,15 +392,6 @@
var u;
SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try {
if(data && data.slice
&& 'SEA{' === data.slice(0,4)
&& '"m":' === data.slice(4,8)){
// TODO: This would prevent pair2 signing pair1's signature.
// So we may want to change this in the future.
// but for now, we want to prevent duplicate double signature.
if(cb){ try{ cb(data) }catch(e){console.log(e)} }
return data;
}
opt = opt || {};
if(!(pair||opt).priv){
pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why});
@ -408,11 +399,10 @@
const pub = pair.pub
const priv = pair.priv
const jwk = S.jwk(pub, priv)
const msg = JSON.stringify(data)
const hash = await sha256hash(msg)
const hash = await sha256hash(JSON.stringify(data))
const 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!
const r = 'SEA'+JSON.stringify({m: msg, s: shim.Buffer.from(sig, 'binary').toString('utf8')});
const r = 'SEA'+JSON.stringify({m: data, s: shim.Buffer.from(sig, 'binary').toString(opt.encode || 'base64')});
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
@ -451,7 +441,9 @@
const jwk = S.jwk(pub)
const key = await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['verify'])
const hash = await sha256hash(json.m)
const sig = new Uint8Array(shim.Buffer.from(json.s, 'utf8'))
var buf; try{buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){buf = shim.Buffer.from(json.s, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
const sig = new Uint8Array(buf)
const check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash))
if(!check){ throw "Signature did not match." }
const r = check? parse(json.m) : u;
@ -503,9 +495,9 @@
name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv)
}, aes, new shim.TextEncoder().encode(msg)))
const r = 'SEA'+JSON.stringify({
ct: shim.Buffer.from(ct, 'binary').toString('utf8'),
iv: rand.iv.toString('utf8'),
s: rand.s.toString('utf8')
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(cb){ try{ cb(r) }catch(e){console.log(e)} }
@ -535,10 +527,18 @@
key = pair.epriv || pair;
}
const json = parse(data)
const ct = await aeskey(key, shim.Buffer.from(json.s, 'utf8'), opt)
var buf; try{buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){buf = shim.Buffer.from(json.s, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
var bufiv; try{bufiv = shim.Buffer.from(json.iv, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){bufiv = shim.Buffer.from(json.iv, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
var bufct; try{bufct = shim.Buffer.from(json.ct, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){bufct = shim.Buffer.from(json.ct, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
const 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(shim.Buffer.from(json.iv, 'utf8'))
}, aes, new Uint8Array(shim.Buffer.from(json.ct, 'utf8'))))
name: opt.name || 'AES-GCM', iv: new Uint8Array(bufiv)
}, aes, new Uint8Array(bufct)))
const r = parse(new shim.TextDecoder('utf8').decode(ct))
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
@ -743,26 +743,30 @@
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){
act.c = function(pair){ var tmp;
act.pair = pair || {};
// the user's public key doesn't need to be signed. But everything else needs to be signed with it!
if(tmp = cat.root.user){
tmp._.sea = pair;
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};
SEA.sign(alias, pair, act.d);
}
act.d = function(alias){
act.data.alias = alias;
act.d = function(sig){
act.data.alias = alias || sig;
SEA.sign(act.pair.epub, act.pair, act.e);
}
act.e = function(epub){
act.data.epub = epub;
act.data.epub = act.pair.epub || epub;
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f); // to keep the private key safe, we AES encrypt it with the proof of work!
}
act.f = function(auth){
act.data.auth = auth;
act.data.auth = JSON.stringify({ek: auth, s: act.salt});
SEA.sign({ek: auth, s: act.salt}, act.pair, act.g);
}
act.g = function(auth){ var tmp;
act.data.auth = auth;
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?
@ -806,14 +810,20 @@
}
act.c = function(auth){
if(u === auth){ return act.b() }
SEA.work(pass, (act.auth = auth).s, act.d); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force.
if(Gun.text.is(auth)){ return act.c(Gun.obj.ify(auth)) } // new format
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){
if(u === proof){ return act.b() }
SEA.decrypt(act.auth.ek, proof, act.e);
SEA.decrypt(act.auth.ek, proof, act.e, act.enc);
}
act.e = function(half){
if(u === half){ return act.b() }
if(u === half){
if(!act.enc){ // try old format
act.enc = {encode: 'utf8'};
return act.c(act.auth);
} act.enc = null; // end backwards
return act.b();
}
act.half = half;
act.f(act.data);
}
@ -833,6 +843,7 @@
user.is = {pub: pair.pub, epub: pair.epub, alias: alias};
at.sea = act.pair;
cat.ing = false;
if(pass && !Gun.text.is(act.data.auth)){ opt.shuffle = opt.change = pass; } // migrate UTF8 + Shuffle! Test against NAB alias test_sea_shuffle + passw0rd
opt.change? act.z() : cb(at);
if(SEA.window && ((gun.back('user')._).opt||opt).remember){
// TODO: this needs to be modular.
@ -859,9 +870,17 @@
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x);
}
act.x = function(auth){
SEA.sign({ek: auth, s: act.salt}, act.pair, act.w);
act.w(JSON.stringify({ek: auth, s: act.salt}));
//SEA.sign({ek: auth, s: act.salt}, act.pair, act.w);
}
act.w = function(auth){
if(opt.shuffle){ // delete in future!
var tmp = Gun.obj.to(act.data);
Gun.obj.del(tmp, '_');
tmp.auth = auth;
console.log('migrate core account from UTF8 & shuffle', tmp);
root.get('~'+act.pair.pub).put(tmp);
} // end delete
root.get('~'+act.pair.pub).get('auth').put(auth, cb);
}
act.err = function(e){
@ -1052,6 +1071,8 @@
Gun.node.is(msg.put, function(val, key, node){ c++; // for each property on the node
// TODO: consider async/await use here...
SEA.verify(val, false, function(data){ c--; // false just extracts the plain data.
var tmp = data;
data = SEA.opt.unpack(data, key, node);
node[key] = val = data; // transform to plain value.
if(d && !c && (c = -1)){ to.next(msg) }
});
@ -1131,7 +1152,7 @@
check['user'+soul+key] = 1;
if(user && user.is && pub === user.is.pub){
//var id = Gun.text.random(3);
SEA.sign(val, (user._).sea, function(data){ var rel;
SEA.sign([soul, key, val, Gun.state.is(node, key)], (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;
@ -1144,6 +1165,7 @@
return;
}
SEA.verify(val, 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.
}
@ -1168,6 +1190,7 @@
if(tmp = relpub(soul)){
check['any'+soul+key] = 1;
SEA.verify(val, pub = tmp, 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 === relpub(rel)){
(at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
@ -1205,7 +1228,7 @@
//});
return;
}
if((pub = tmp) !== (user.is||noop).pub){
if(!msg.I || (pub = tmp) !== (user.is||noop).pub){
each.any(val, key, node, soul);
return;
}
@ -1217,7 +1240,7 @@
return;
}*/
check['any'+soul+key] = 1;
SEA.sign(val, (user._).sea, function(data){
SEA.sign([soul, key, val, Gun.state.is(node, key)], (user._).sea, function(data){
if(u === data){ return each.end({err: 'My signature fail.'}) }
node[key] = data;
check['any'+soul+key] = 0;
@ -1242,7 +1265,18 @@
}
to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols).
}
var noop = {};
SEA.opt.unpack = function(data, key, node){
if(u === data){ return }
var tmp = data, soul = Gun.node.soul(node), s = Gun.state.is(node, key);
if(tmp && 4 === tmp.length && soul === tmp[0] && key === tmp[1] && s === tmp[3]){
return tmp[2];
}
if(s < SEA.opt.shuffle_attack){
return data;
}
}
SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019
var noop = {}, u;
})(USE, './index');
}());

View File

@ -37,26 +37,30 @@
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){
act.c = function(pair){ var tmp;
act.pair = pair || {};
// the user's public key doesn't need to be signed. But everything else needs to be signed with it!
if(tmp = cat.root.user){
tmp._.sea = pair;
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};
SEA.sign(alias, pair, act.d);
}
act.d = function(alias){
act.data.alias = alias;
act.d = function(sig){
act.data.alias = alias || sig;
SEA.sign(act.pair.epub, act.pair, act.e);
}
act.e = function(epub){
act.data.epub = epub;
act.data.epub = act.pair.epub || epub;
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, act.proof, act.f); // to keep the private key safe, we AES encrypt it with the proof of work!
}
act.f = function(auth){
act.data.auth = auth;
act.data.auth = JSON.stringify({ek: auth, s: act.salt});
SEA.sign({ek: auth, s: act.salt}, act.pair, act.g);
}
act.g = function(auth){ var tmp;
act.data.auth = auth;
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?
@ -78,7 +82,7 @@
}
cat.ing = true;
opt = opt || {};
var pair = (alias.pub || alias.epub)? alias : (pass.pub || pass.epub)? pass : null;
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() }
@ -100,14 +104,20 @@
}
act.c = function(auth){
if(u === auth){ return act.b() }
SEA.work(pass, (act.auth = auth).s, act.d); // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force.
if(Gun.text.is(auth)){ return act.c(Gun.obj.ify(auth)) } // new format
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){
if(u === proof){ return act.b() }
SEA.decrypt(act.auth.ek, proof, act.e);
SEA.decrypt(act.auth.ek, proof, act.e, act.enc);
}
act.e = function(half){
if(u === half){ return act.b() }
if(u === half){
if(!act.enc){ // try old format
act.enc = {encode: 'utf8'};
return act.c(act.auth);
} act.enc = null; // end backwards
return act.b();
}
act.half = half;
act.f(act.data);
}
@ -127,13 +137,16 @@
user.is = {pub: pair.pub, epub: pair.epub, alias: alias};
at.sea = act.pair;
cat.ing = false;
if(pass && !Gun.text.is(act.data.auth)){ opt.shuffle = opt.change = pass; } // migrate UTF8 + Shuffle! Test against NAB alias test_sea_shuffle + passw0rd
opt.change? act.z() : cb(at);
if(SEA.window && ((gun.back('user')._).opt||opt).remember){
// TODO: this needs to be modular.
var sS = {}; try{sS = window.sessionStorage}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.
@ -151,9 +164,17 @@
SEA.encrypt({priv: act.pair.priv, epriv: act.pair.epriv}, proof, act.x);
}
act.x = function(auth){
SEA.sign({ek: auth, s: act.salt}, act.pair, act.w);
act.w(JSON.stringify({ek: auth, s: act.salt}));
//SEA.sign({ek: auth, s: act.salt}, act.pair, act.w);
}
act.w = function(auth){
if(opt.shuffle){ // delete in future!
var tmp = Gun.obj.to(act.data);
Gun.obj.del(tmp, '_');
tmp.auth = auth;
console.log('migrate core account from UTF8 & shuffle', tmp);
root.get('~'+act.pair.pub).put(tmp);
} // end delete
root.get('~'+act.pair.pub).get('auth').put(auth, cb);
}
act.err = function(e){
@ -195,10 +216,12 @@
delete user._.sea;
}
if(SEA.window){
var sS = {}; try{sS = window.sessionStorage}catch(e){};
try{var sS = {};
sS = window.sessionStorage;
delete sS.alias;
delete sS.tmp;
delete sS.recall;
}catch(e){};
}
return gun;
}
@ -224,7 +247,8 @@
opt = opt || {};
if(opt && opt.sessionStorage){
if(SEA.window){
var sS = {}; try{sS = window.sessionStorage}catch(e){}
try{var sS = {};
sS = window.sessionStorage;
if(sS){
(root._).opt.remember = true;
((gun.back('user')._).opt||opt).remember = true;
@ -232,6 +256,7 @@
root.user().auth(sS.alias, sS.tmp, cb);
}
}
}catch(e){}
}
return gun;
}

View File

@ -13,15 +13,24 @@
key = pair.epriv || pair;
}
const json = parse(data)
const ct = await aeskey(key, shim.Buffer.from(json.s, 'utf8'), opt)
var buf; try{buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){buf = shim.Buffer.from(json.s, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
var bufiv; try{bufiv = shim.Buffer.from(json.iv, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){bufiv = shim.Buffer.from(json.iv, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
var bufct; try{bufct = shim.Buffer.from(json.ct, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){bufct = shim.Buffer.from(json.ct, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
const 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(shim.Buffer.from(json.iv, 'utf8'))
}, aes, new Uint8Array(shim.Buffer.from(json.ct, 'utf8'))))
name: opt.name || 'AES-GCM', iv: new Uint8Array(bufiv)
}, aes, new Uint8Array(bufct)))
const r = parse(new shim.TextDecoder('utf8').decode(ct))
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -18,15 +18,16 @@
name: opt.name || 'AES-GCM', iv: new Uint8Array(rand.iv)
}, aes, new shim.TextEncoder().encode(msg)))
const r = 'SEA'+JSON.stringify({
ct: shim.Buffer.from(ct, 'binary').toString('utf8'),
iv: rand.iv.toString('utf8'),
s: rand.s.toString('utf8')
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(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -1,10 +1,10 @@
var SEA = require('./root');
if(SEA.window){
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){}

View File

@ -34,6 +34,8 @@
Gun.node.is(msg.put, function(val, key, node){ c++; // for each property on the node
// TODO: consider async/await use here...
SEA.verify(val, false, function(data){ c--; // false just extracts the plain data.
var tmp = data;
data = SEA.opt.unpack(data, key, node);
node[key] = val = data; // transform to plain value.
if(d && !c && (c = -1)){ to.next(msg) }
});
@ -77,7 +79,7 @@
// 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. @amark, removing this line solves issue #616. 2018-10-02
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){
@ -113,7 +115,7 @@
check['user'+soul+key] = 1;
if(user && user.is && pub === user.is.pub){
//var id = Gun.text.random(3);
SEA.sign(val, (user._).sea, function(data){ var rel;
SEA.sign([soul, key, val, Gun.state.is(node, key)], (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;
@ -126,6 +128,7 @@
return;
}
SEA.verify(val, 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.
}
@ -150,6 +153,7 @@
if(tmp = relpub(soul)){
check['any'+soul+key] = 1;
SEA.verify(val, pub = tmp, 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 === relpub(rel)){
(at.sea.own[rel] = at.sea.own[rel] || {})[pub] = true;
@ -187,7 +191,7 @@
//});
return;
}
if((pub = tmp) !== (user.is||noop).pub){
if(!msg.I || (pub = tmp) !== (user.is||noop).pub){
each.any(val, key, node, soul);
return;
}
@ -199,7 +203,7 @@
return;
}*/
check['any'+soul+key] = 1;
SEA.sign(val, (user._).sea, function(data){
SEA.sign([soul, key, val, Gun.state.is(node, key)], (user._).sea, function(data){
if(u === data){ return each.end({err: 'My signature fail.'}) }
node[key] = data;
check['any'+soul+key] = 0;
@ -224,6 +228,17 @@
}
to.next(msg); // pass forward any data we do not know how to handle or process (this allows custom security protocols).
}
var noop = {};
SEA.opt.unpack = function(data, key, node){
if(u === data){ return }
var tmp = data, soul = Gun.node.soul(node), s = Gun.state.is(node, key);
if(tmp && 4 === tmp.length && soul === tmp[0] && key === tmp[1] && s === tmp[3]){
return tmp[2];
}
if(s < SEA.opt.shuffle_attack){
return data;
}
}
SEA.opt.shuffle_attack = 1546329600000; // Jan 1, 2019
var noop = {}, u;

View File

@ -10,6 +10,7 @@
} catch(e) {
console.log(e);
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});
@ -64,6 +65,7 @@
} catch(e) {
console.log(e);
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -1,44 +1,18 @@
// Old Code...
try{
const __gky10 = require('./shim')
const crypto = __gky10.crypto
const subtle = __gky10.subtle
const ossl = __gky10.ossl
const TextEncoder = __gky10.TextEncoder
const TextDecoder = __gky10.TextDecoder
const getRandomBytes = __gky10.random
const EasyIndexedDB = require('./indexed')
const Buffer = require('./buffer')
var settings = require('./settings');
const __gky11 = require('./settings')
const pbKdf2 = __gky11.pbkdf2
const ecdsaKeyProps = __gky11.ecdsa.pair
const ecdsaSignProps = __gky11.ecdsa.sign
const ecdhKeyProps = __gky11.ecdh
const keysToEcdsaJwk = __gky11.jwk
const sha1hash = require('./sha1')
const sha256hash = require('./sha256')
const parseProps = require('./parse')
}catch(e){}
var shim = require('./shim');
// Practical examples about usage found from ./test/common.js
const SEA = require('./root');
var SEA = require('./root');
SEA.work = require('./work');
SEA.sign = require('./sign');
SEA.verify = require('./verify');
SEA.encrypt = require('./encrypt');
SEA.decrypt = require('./decrypt');
SEA.random = SEA.random || getRandomBytes;
// This is easy way to use IndexedDB, all methods are Promises
// Note: Not all SEA interfaces have to support this.
SEA.EasyIndexedDB = EasyIndexedDB;
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 || Buffer;
SEA.Buffer = SEA.Buffer || require('./buffer');
// These SEA functions support now ony Promises or
// async/await (compatible) code, use those like Promises.

View File

@ -29,6 +29,7 @@
return r;
} catch(e) {
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -3,17 +3,9 @@
var shim = require('./shim');
var S = require('./settings');
var sha256hash = require('./sha256');
var u;
SEA.sign = SEA.sign || (async (data, pair, cb, opt) => { try {
if(data && data.slice
&& 'SEA{' === data.slice(0,4)
&& '"m":' === data.slice(4,8)){
// TODO: This would prevent pair2 signing pair1's signature.
// So we may want to change this in the future.
// but for now, we want to prevent duplicate double signature.
if(cb){ try{ cb(data) }catch(e){console.log(e)} }
return data;
}
opt = opt || {};
if(!(pair||opt).priv){
pair = await SEA.I(null, {what: data, how: 'sign', why: opt.why});
@ -21,17 +13,17 @@
const pub = pair.pub
const priv = pair.priv
const jwk = S.jwk(pub, priv)
const msg = JSON.stringify(data)
const hash = await sha256hash(msg)
const hash = await sha256hash(JSON.stringify(data))
const 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!
const r = 'SEA'+JSON.stringify({m: msg, s: shim.Buffer.from(sig, 'binary').toString('utf8')});
const r = 'SEA'+JSON.stringify({m: data, s: shim.Buffer.from(sig, '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;
}});

View File

@ -22,7 +22,9 @@
const jwk = S.jwk(pub)
const key = await (shim.ossl || shim.subtle).importKey('jwk', jwk, S.ecdsa.pair, false, ['verify'])
const hash = await sha256hash(json.m)
const sig = new Uint8Array(shim.Buffer.from(json.s, 'utf8'))
var buf; try{buf = shim.Buffer.from(json.s, opt.encode || 'base64') // NEW DEFAULT!
}catch(e){buf = shim.Buffer.from(json.s, 'utf8')} // AUTO BACKWARD OLD UTF8 DATA!
const sig = new Uint8Array(buf)
const check = await (shim.ossl || shim.subtle).verify(S.ecdsa.sign, key, sig, new Uint8Array(hash))
if(!check){ throw "Signature did not match." }
const r = check? parse(json.m) : u;
@ -32,6 +34,7 @@
} catch(e) {
console.log(e); // mismatched owner FOR MARTTI
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -14,7 +14,7 @@
}
salt = salt || shim.random(9);
if('SHA-256' === opt.name){
var rsha = shim.Buffer.from(await sha(data), 'binary').toString('utf8')
var rsha = shim.Buffer.from(await sha(data), 'binary').toString(opt.encode || 'base64')
if(cb){ try{ cb(rsha) }catch(e){console.log(e)} }
return rsha;
}
@ -28,11 +28,12 @@
hash: opt.hash || S.pbkdf2.hash,
}, key, opt.length || (S.pbkdf2.ks * 8))
data = shim.random(data.length) // Erase data in case of passphrase
const r = shim.Buffer.from(result, 'binary').toString('utf8')
const r = shim.Buffer.from(result, 'binary').toString(opt.encode || 'base64')
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
return r;
} catch(e) {
SEA.err = e;
if(SEA.throw){ throw e }
if(cb){ cb() }
return;
}});

View File

@ -5,7 +5,7 @@ var root, noop = function(){}, store, u;
try{store = (Gun.window||noop).localStorage}catch(e){}
if(!store){
console.log("Warning: No localStorage exists to persist data to!");
store = {setItem: noop, removeItem: noop, getItem: noop};
store = {setItem: function(k,v){this[k]=v}, removeItem: function(k){delete this[k]}, getItem: function(k){return this[k]}};
}
/*
NOTE: Both `lib/file.js` and `lib/memdisk.js` are based on this design!

View File

@ -20,7 +20,7 @@ function Mesh(ctx){
return;
}
// add hook for AXE?
if (Gun.AXE && opt && opt.super) { Gun.AXE.say(msg, mesh.say, this); return; }
//if (Gun.AXE && opt && opt.super) { Gun.AXE.say(msg, mesh.say, this); return; } // rogowski
mesh.say(msg);
}
@ -229,3 +229,5 @@ Mesh.hash = function(s){ // via SO
Object.keys = Object.keys || function(o){ return map(o, function(v,k,t){t(k)}) }
try{ module.exports = Mesh }catch(e){}

View File

@ -93,9 +93,10 @@ function use(msg){
msg = obj_to(msg, {put: data = tmp.put});
}
}
if((tmp = root.mum) && at.id){
if(tmp[at.id]){ return }
if(u !== data && !rel.is(data)){ tmp[at.id] = true; }
if((tmp = root.mum) && at.id){ // TODO: can we delete mum entirely now?
var id = at.id + (eve.id || (eve.id = Gun.text.random(9)));
if(tmp[id]){ return }
if(u !== data && !rel.is(data)){ tmp[id] = true; }
}
as.use(msg, eve);
if(eve.stun){