|
@@ -6,8 +6,8 @@
|
|
|
if(typeof global !== "undefined"){ root = global }
|
|
|
root = root || {};
|
|
|
var console = root.console || {log: function(){}};
|
|
|
- function USE(arg){
|
|
|
- return arg.slice? USE[R(arg)] : function(mod, path){
|
|
|
+ function USE(arg, req){
|
|
|
+ return req? require(arg) : arg.slice? USE[R(arg)] : function(mod, path){
|
|
|
arg(mod = {exports: {}});
|
|
|
USE[R(path)] = mod.exports;
|
|
|
}
|
|
@@ -20,12 +20,24 @@
|
|
|
|
|
|
;USE(function(module){
|
|
|
// Security, Encryption, and Authorization: SEA.js
|
|
|
- // MANDATORY READING: http://gun.js.org/explainers/data/security.html
|
|
|
+ // MANDATORY READING: https://gun.eco/explainers/data/security.html
|
|
|
+ // IT IS IMPLEMENTED IN A POLYFILL/SHIM APPROACH.
|
|
|
// THIS IS AN EARLY ALPHA!
|
|
|
|
|
|
- function SEA(){}
|
|
|
- if(typeof window !== "undefined"){ (SEA.window = window).SEA = SEA }
|
|
|
+ if(typeof window !== "undefined"){ module.window = window }
|
|
|
|
|
|
+ var tmp = module.window || module;
|
|
|
+ var SEA = tmp.SEA || function(){};
|
|
|
+
|
|
|
+ if(SEA.window = module.window){ try{
|
|
|
+ SEA.window.SEA = SEA;
|
|
|
+ tmp = document.createEvent('CustomEvent');
|
|
|
+ tmp.initCustomEvent('extension', false, false, {type: "SEA"});
|
|
|
+ (window.dispatchEvent || window.fireEvent)(tmp);
|
|
|
+ window.postMessage({type: "SEA"}, '*');
|
|
|
+ } catch(e){} }
|
|
|
+
|
|
|
+ try{ if(typeof common !== "undefined"){ common.exports = SEA } }catch(e){}
|
|
|
module.exports = SEA;
|
|
|
})(USE, './root');
|
|
|
|
|
@@ -148,7 +160,7 @@
|
|
|
const Buffer = USE('./buffer')
|
|
|
const api = {Buffer: Buffer}
|
|
|
|
|
|
- if (typeof __webpack_require__ === 'function' || typeof window !== 'undefined') {
|
|
|
+ if (typeof window !== 'undefined') {
|
|
|
var crypto = window.crypto || window.msCrypto;
|
|
|
var subtle = crypto.subtle || crypto.webkitSubtle;
|
|
|
const TextEncoder = window.TextEncoder
|
|
@@ -162,9 +174,9 @@
|
|
|
})
|
|
|
} else {
|
|
|
try{
|
|
|
- var crypto = require('crypto');
|
|
|
- const { subtle } = require('@trust/webcrypto') // All but ECDH
|
|
|
- const { TextEncoder, TextDecoder } = require('text-encoding')
|
|
|
+ var crypto = USE('crypto', 1);
|
|
|
+ const { subtle } = USE('@trust/webcrypto', 1) // All but ECDH
|
|
|
+ const { TextEncoder, TextDecoder } = USE('text-encoding', 1)
|
|
|
Object.assign(api, {
|
|
|
crypto,
|
|
|
subtle,
|
|
@@ -173,7 +185,7 @@
|
|
|
random: (len) => Buffer.from(crypto.randomBytes(len))
|
|
|
});
|
|
|
//try{
|
|
|
- const WebCrypto = require('node-webcrypto-ossl')
|
|
|
+ const WebCrypto = USE('node-webcrypto-ossl', 1)
|
|
|
api.ossl = new WebCrypto({directory: 'ossl'}).subtle // ECDH
|
|
|
//}catch(e){
|
|
|
//console.log("node-webcrypto-ossl is optionally needed for ECDH, please install if needed.");
|
|
@@ -189,6 +201,7 @@
|
|
|
})(USE, './shim');
|
|
|
|
|
|
;USE(function(module){
|
|
|
+ const SEA = USE('./root');
|
|
|
const Buffer = USE('./buffer')
|
|
|
const settings = {}
|
|
|
// Encryption parameters
|
|
@@ -225,6 +238,7 @@
|
|
|
jwk: keysToEcdsaJwk,
|
|
|
recall: authsettings
|
|
|
})
|
|
|
+ SEA.opt = settings;
|
|
|
module.exports = settings
|
|
|
})(USE, './settings');
|
|
|
|
|
@@ -267,49 +281,40 @@
|
|
|
var SEA = USE('./root');
|
|
|
var shim = USE('./shim');
|
|
|
var S = USE('./settings');
|
|
|
+ var sha = USE('./sha256');
|
|
|
var u;
|
|
|
|
|
|
- SEA.work = async (data, pair, cb) => { try { // used to be named `proof`
|
|
|
- var salt = pair.epub || pair; // epub not recommended, salt should be random!
|
|
|
+ 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);
|
|
|
- if (SEA.window) {
|
|
|
- // For browser subtle works fine
|
|
|
- const key = await shim.subtle.importKey(
|
|
|
- 'raw', new shim.TextEncoder().encode(data), { name: 'PBKDF2' }, false, ['deriveBits']
|
|
|
- )
|
|
|
- const result = await shim.subtle.deriveBits({
|
|
|
- name: 'PBKDF2',
|
|
|
- iterations: S.pbkdf2.iter,
|
|
|
- salt: new shim.TextEncoder().encode(salt),
|
|
|
- hash: S.pbkdf2.hash,
|
|
|
- }, key, S.pbkdf2.ks * 8)
|
|
|
- data = shim.random(data.length) // Erase data in case of passphrase
|
|
|
- const r = shim.Buffer.from(result, 'binary').toString('utf8')
|
|
|
- if(cb){ try{ cb(r) }catch(e){console.log(e)} }
|
|
|
- return r;
|
|
|
+ if('SHA-256' === opt.name){
|
|
|
+ var rsha = shim.Buffer.from(await sha(data), 'binary').toString('utf8')
|
|
|
+ if(cb){ try{ cb(rsha) }catch(e){console.log(e)} }
|
|
|
+ return rsha;
|
|
|
}
|
|
|
- // For NodeJS crypto.pkdf2 rocks
|
|
|
- const crypto = shim.crypto;
|
|
|
- const hash = crypto.pbkdf2Sync(
|
|
|
- data,
|
|
|
- new shim.TextEncoder().encode(salt),
|
|
|
- S.pbkdf2.iter,
|
|
|
- S.pbkdf2.ks,
|
|
|
- S.pbkdf2.hash.replace('-', '').toLowerCase()
|
|
|
+ const key = await (shim.ossl || shim.subtle).importKey(
|
|
|
+ 'raw', new shim.TextEncoder().encode(data), { name: opt.name || 'PBKDF2' }, false, ['deriveBits']
|
|
|
)
|
|
|
- data = shim.random(data.length) // Erase passphrase for app
|
|
|
- const r = hash && hash.toString('utf8')
|
|
|
+ const result = 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
|
|
|
+ const r = shim.Buffer.from(result, 'binary').toString('utf8')
|
|
|
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
|
|
|
return r;
|
|
|
} catch(e) {
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.work;
|
|
|
})(USE, './work');
|
|
@@ -321,7 +326,7 @@
|
|
|
var Buff = (typeof Buffer !== 'undefined')? Buffer : shim.Buffer;
|
|
|
|
|
|
//SEA.pair = async (data, proof, cb) => { try {
|
|
|
- SEA.pair = async (cb) => { try {
|
|
|
+ SEA.pair = SEA.pair || (async (cb) => { try {
|
|
|
|
|
|
const ecdhSubtle = shim.ossl || shim.subtle
|
|
|
// First: ECDSA keys for signing/verifying...
|
|
@@ -372,7 +377,7 @@
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.pair;
|
|
|
})(USE, './pair');
|
|
@@ -383,7 +388,7 @@
|
|
|
var S = USE('./settings');
|
|
|
var sha256hash = USE('./sha256');
|
|
|
|
|
|
- SEA.sign = async (data, pair, cb) => { try {
|
|
|
+ SEA.sign = SEA.sign || (async (data, pair, cb) => { try {
|
|
|
if(data && data.slice
|
|
|
&& 'SEA{' === data.slice(0,4)
|
|
|
&& '"m":' === data.slice(4,8)){
|
|
@@ -409,7 +414,7 @@
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.sign;
|
|
|
})(USE, './sign');
|
|
@@ -422,7 +427,7 @@
|
|
|
var parse = USE('./parse');
|
|
|
var u;
|
|
|
|
|
|
- SEA.verify = async (data, pair, cb) => { try {
|
|
|
+ SEA.verify = SEA.verify || (async (data, pair, cb) => { try {
|
|
|
const json = parse(data)
|
|
|
if(false === pair){ // don't verify!
|
|
|
const raw = (json !== data)?
|
|
@@ -447,7 +452,7 @@
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.verify;
|
|
|
})(USE, './verify');
|
|
@@ -472,13 +477,13 @@
|
|
|
var S = USE('./settings');
|
|
|
var aeskey = USE('./aeskey');
|
|
|
|
|
|
- SEA.encrypt = async (data, pair, cb, opt) => { try {
|
|
|
+ SEA.encrypt = SEA.encrypt || (async (data, pair, cb, opt) => { try {
|
|
|
var opt = opt || {};
|
|
|
const key = pair.epriv || pair;
|
|
|
const msg = JSON.stringify(data)
|
|
|
const rand = {s: shim.random(8), iv: shim.random(16)};
|
|
|
const ct = await aeskey(key, rand.s, opt)
|
|
|
- .then((aes) => shim.subtle.encrypt({ // Keeping the AES key scope as private as possible...
|
|
|
+ .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)))
|
|
|
const r = 'SEA'+JSON.stringify({
|
|
@@ -493,7 +498,7 @@
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.encrypt;
|
|
|
})(USE, './encrypt');
|
|
@@ -505,23 +510,22 @@
|
|
|
var aeskey = USE('./aeskey');
|
|
|
var parse = USE('./parse');
|
|
|
|
|
|
- SEA.decrypt = async (data, pair, cb, opt) => { try {
|
|
|
+ SEA.decrypt = SEA.decrypt || (async (data, pair, cb, opt) => { try {
|
|
|
var opt = opt || {};
|
|
|
const key = pair.epriv || pair;
|
|
|
const json = parse(data)
|
|
|
const ct = await aeskey(key, shim.Buffer.from(json.s, 'utf8'), opt)
|
|
|
- .then((aes) => shim.subtle.decrypt({ // Keeping aesKey scope as private as possible...
|
|
|
+ .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'))))
|
|
|
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(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
module.exports = SEA.decrypt;
|
|
|
})(USE, './decrypt');
|
|
@@ -531,7 +535,7 @@
|
|
|
var shim = USE('./shim');
|
|
|
var S = USE('./settings');
|
|
|
// Derive shared secret from other's pub and my epub/epriv
|
|
|
- SEA.secret = async (key, pair, cb) => { try {
|
|
|
+ SEA.secret = SEA.secret || (async (key, pair, cb) => { try {
|
|
|
const pub = key.epub || key
|
|
|
const epub = pair.epub
|
|
|
const epriv = pair.epriv
|
|
@@ -555,7 +559,7 @@
|
|
|
SEA.err = e;
|
|
|
if(cb){ cb() }
|
|
|
return;
|
|
|
- }}
|
|
|
+ }});
|
|
|
|
|
|
const keysToEcdhJwk = (pub, d) => { // d === priv
|
|
|
//const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old
|
|
@@ -605,7 +609,7 @@
|
|
|
SEA.encrypt = USE('./encrypt');
|
|
|
SEA.decrypt = USE('./decrypt');
|
|
|
|
|
|
- SEA.random = getRandomBytes;
|
|
|
+ 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.
|
|
@@ -613,7 +617,7 @@
|
|
|
|
|
|
// This is Buffer used in SEA and usable from Gun/SEA application also.
|
|
|
// For documentation see https://nodejs.org/api/buffer.html
|
|
|
- SEA.Buffer = Buffer;
|
|
|
+ SEA.Buffer = SEA.Buffer || Buffer;
|
|
|
|
|
|
// These SEA functions support now ony Promises or
|
|
|
// async/await (compatible) code, use those like Promises.
|
|
@@ -621,7 +625,7 @@
|
|
|
// 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 = async (pub) => {
|
|
|
+ SEA.keyid = SEA.keyid || (async (pub) => {
|
|
|
try {
|
|
|
// base64('base64(x):base64(y)') => Buffer(xy)
|
|
|
const pb = Buffer.concat(
|
|
@@ -639,7 +643,7 @@
|
|
|
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.
|
|
@@ -649,7 +653,7 @@
|
|
|
// 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 || require('./gun');
|
|
|
+ var Gun = (SEA.window||{}).Gun || USE('./gun', 1);
|
|
|
Gun.SEA = SEA;
|
|
|
SEA.Gun = Gun;
|
|
|
|
|
@@ -662,9 +666,9 @@
|
|
|
// This is internal func queries public key(s) for alias.
|
|
|
const queryGunAliases = (alias, gunRoot) => new Promise((resolve, reject) => {
|
|
|
// load all public keys associated with the username alias we want to log in with.
|
|
|
- gunRoot.get('~@'+alias).get((rat, rev) => {
|
|
|
- rev.off();
|
|
|
- if (!rat.put) {
|
|
|
+ gunRoot.get('~@'+alias).once((data, key) => {
|
|
|
+ //rev.off();
|
|
|
+ if (!data) {
|
|
|
// if no user, don't do anything.
|
|
|
const err = 'No user!'
|
|
|
Gun.log(err)
|
|
@@ -674,19 +678,18 @@
|
|
|
const aliases = []
|
|
|
let c = 0
|
|
|
// TODO: how about having real chainable map without callback ?
|
|
|
- Gun.obj.map(rat.put, (at, pub) => {
|
|
|
+ Gun.obj.map(data, (at, pub) => {
|
|
|
if (!pub.slice || '~' !== pub.slice(0, 1)) {
|
|
|
// TODO: ... this would then be .filter((at, pub))
|
|
|
return
|
|
|
}
|
|
|
++c
|
|
|
// grab the account associated with this public key.
|
|
|
- gunRoot.get(pub).get((at, ev) => {
|
|
|
+ gunRoot.get(pub).once(data => {
|
|
|
pub = pub.slice(1)
|
|
|
- ev.off()
|
|
|
--c
|
|
|
- if (at.put){
|
|
|
- aliases.push({ pub, at })
|
|
|
+ if (data){
|
|
|
+ aliases.push({ pub, put: data })
|
|
|
}
|
|
|
if (!c && (c = -1)) {
|
|
|
resolve(aliases)
|
|
@@ -710,7 +713,7 @@
|
|
|
const authenticate = async (alias, pass, gunRoot) => {
|
|
|
// load all public keys associated with the username alias we want to log in with.
|
|
|
const aliases = (await queryGunAliases(alias, gunRoot))
|
|
|
- .filter(({ pub, at: { put } = {} } = {}) => !!pub && !!put)
|
|
|
+ .filter(a => !!a.pub && !!a.put)
|
|
|
// Got any?
|
|
|
if (!aliases.length) {
|
|
|
throw { err: 'Public key does not exist!' }
|
|
@@ -718,14 +721,14 @@
|
|
|
let err
|
|
|
// then attempt to log into each one until we find ours!
|
|
|
// (if two users have the same username AND the same password... that would be bad)
|
|
|
- const users = await Promise.all(aliases.map(async ({ at: at, pub: pub }, i) => {
|
|
|
+ const users = await Promise.all(aliases.map(async (a, i) => {
|
|
|
// attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.)
|
|
|
- const auth = parseProps(at.put.auth)
|
|
|
+ const auth = parseProps(a.put.auth)
|
|
|
// NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here.
|
|
|
// SEA.verify(at.put.auth, pub).then(function(auth){
|
|
|
try {
|
|
|
const proof = await SEA.work(pass, auth.s)
|
|
|
- const props = { pub: pub, proof: proof, at: at }
|
|
|
+ //const props = { pub: pub, proof: proof, at: at }
|
|
|
// the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force.
|
|
|
/*
|
|
|
MARK TO @mhelander : pub vs epub!???
|
|
@@ -733,24 +736,24 @@
|
|
|
const salt = auth.salt
|
|
|
const sea = await SEA.decrypt(auth.ek, proof)
|
|
|
if (!sea) {
|
|
|
- err = 'Failed to decrypt secret! ' + i +'/'+aliases.length;
|
|
|
+ err = 'Failed to decrypt secret! ' + (i+1) +'/'+aliases.length;
|
|
|
return
|
|
|
}
|
|
|
// now we have AES decrypted the private key, from when we encrypted it with the proof at registration.
|
|
|
// if we were successful, then that meanswe're logged in!
|
|
|
const priv = sea.priv
|
|
|
const epriv = sea.epriv
|
|
|
- const epub = at.put.epub
|
|
|
+ const epub = a.put.epub
|
|
|
// TODO: 'salt' needed?
|
|
|
err = null
|
|
|
- if(typeof window !== 'undefined'){
|
|
|
- var tmp = window.sessionStorage;
|
|
|
+ if(SEA.window){
|
|
|
+ var tmp = SEA.window.sessionStorage;
|
|
|
if(tmp && gunRoot._.opt.remember){
|
|
|
- window.sessionStorage.alias = alias;
|
|
|
- window.sessionStorage.tmp = pass;
|
|
|
+ SEA.window.sessionStorage.alias = alias;
|
|
|
+ SEA.window.sessionStorage.tmp = pass;
|
|
|
}
|
|
|
}
|
|
|
- return Object.assign(props, { priv: priv, salt: salt, epub: epub, epriv: epriv })
|
|
|
+ return {priv: priv, pub: a.put.pub, salt: salt, epub: epub, epriv: epriv };
|
|
|
} catch (e) {
|
|
|
err = 'Failed to decrypt secret!'
|
|
|
throw { err }
|
|
@@ -862,10 +865,25 @@
|
|
|
const finalizeLogin = async (alias, key, gunRoot, opts) => {
|
|
|
const user = gunRoot._.user
|
|
|
// add our credentials in-memory only to our root gun instance
|
|
|
- //var tmp = user._.tag;
|
|
|
+ var tmp = user._.tag;
|
|
|
var opt = user._.opt;
|
|
|
- user._ = key.at.$._;
|
|
|
+ user._ = gunRoot.get('~'+key.pub)._;
|
|
|
user._.opt = opt;
|
|
|
+ var tags = user._.tag;
|
|
|
+ /*Object.values && Object.values(tmp).forEach(function(tag){
|
|
|
+ // TODO: This is ugly & buggy code, it needs to be refactored & tested into a event "merge" utility.
|
|
|
+ var t = tags[tag.tag];
|
|
|
+ console.log("hm??", tag, t);
|
|
|
+ if(!t){
|
|
|
+ tags[tag.tag] = tag;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(tag.last){
|
|
|
+ tag.last.to = t.to;
|
|
|
+ t.last = tag.last = t.last || tag.last;
|
|
|
+ }
|
|
|
+ t.to = tag.to;
|
|
|
+ })*/
|
|
|
//user._.tag = tmp || user._.tag;
|
|
|
// so that way we can use the credentials to encrypt/decrypt data
|
|
|
// that is input/output through gun (see below)
|
|
@@ -880,7 +898,8 @@
|
|
|
//await authPersist(user._, key.proof, opts) // temporarily disabled
|
|
|
// emit an auth event, useful for page redirects and stuff.
|
|
|
try {
|
|
|
- gunRoot._.on('auth', user._)
|
|
|
+ gunRoot._.on('auth', user._) // TODO: Deprecate this, emit on user instead! Update docs when you do.
|
|
|
+ //user._.on('auth', user._) // 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) {
|
|
|
console.log('Your \'auth\' callback crashed with:', e)
|
|
|
}
|
|
@@ -1300,7 +1319,8 @@
|
|
|
}
|
|
|
// If authentication is to be remembered over reloads or browser closing,
|
|
|
// set validity time in minutes.
|
|
|
- User.prototype.recall = async function(setvalidity, options){
|
|
|
+ User.prototype.recall = function(setvalidity, options){
|
|
|
+ var gun = this;
|
|
|
const gunRoot = this.back(-1)
|
|
|
|
|
|
let validity
|
|
@@ -1317,7 +1337,7 @@
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return this;
|
|
|
+ return gun;
|
|
|
}
|
|
|
|
|
|
if (!Gun.val.is(setvalidity)) {
|
|
@@ -1340,13 +1360,15 @@
|
|
|
authsettings.hook = (Gun.obj.has(opts, 'hook') && typeof opts.hook === 'function')
|
|
|
? opts.hook : _initial_authsettings.hook
|
|
|
// All is good. Should we do something more with actual recalled data?
|
|
|
- return await authRecall(gunRoot)
|
|
|
+ (async function(){ await authRecall(gunRoot) }());
|
|
|
+ return gun;
|
|
|
} catch (e) {
|
|
|
const err = 'No session!'
|
|
|
Gun.log(err)
|
|
|
// NOTE! It's fine to resolve recall with reason why not successful
|
|
|
// instead of rejecting...
|
|
|
- return { err: (e && e.err) || err }
|
|
|
+ //return { err: (e && e.err) || err }
|
|
|
+ return gun;
|
|
|
}
|
|
|
}
|
|
|
User.prototype.alive = async function(){
|
|
@@ -1563,7 +1585,7 @@
|
|
|
if(tmp = relpub(soul)){
|
|
|
check['any'+soul+key] = 1;
|
|
|
SEA.verify(val, pub = tmp, function(data){ var rel;
|
|
|
- if(!data){ return each.end({err: "Mismatched owner on '" + key + "'."}) }
|
|
|
+ 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;
|
|
|
}
|