mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
Merge pull request #434 from amark/sea
Major SEA upgrade to use Web Cryptography API and IndexedDB without bulk of modules
This commit is contained in:
commit
f6c02c87fe
29
.eslintrc
Normal file
29
.eslintrc
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": [
|
||||
"standard",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"babel",
|
||||
"promise"
|
||||
],
|
||||
"env": {
|
||||
"browser" : true
|
||||
},
|
||||
"globals": {
|
||||
"__DEV__" : false,
|
||||
"__TEST__" : false,
|
||||
"__PROD__" : false,
|
||||
"__COVERAGE__" : false
|
||||
},
|
||||
"rules": {
|
||||
"key-spacing" : 0,
|
||||
"jsx-quotes" : [2, "prefer-single"],
|
||||
"max-len" : [2, 80, 2],
|
||||
"object-curly-spacing" : [2, "always"],
|
||||
"semi" : [2, "never"],
|
||||
"no-mixed-spaces-and-tabs": [2],
|
||||
"arrow-parens" : [2, "always"]
|
||||
}
|
||||
}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -8,3 +8,6 @@ yarn.lock
|
||||
*.bak
|
||||
*.new
|
||||
*.DS_store
|
||||
.esm-cache
|
||||
.sessionStorage
|
||||
.localStorage
|
||||
|
14
.travis.yml
14
.travis.yml
@ -1,9 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.11
|
||||
- 0.12
|
||||
- 4.0
|
||||
- 4.2
|
||||
- 5.0
|
||||
- 6.8
|
||||
- 7.9
|
||||
language: node_js
|
||||
node_js:
|
||||
- 6.8
|
||||
- 7.9
|
||||
- 8.7.0
|
||||
|
@ -34,7 +34,7 @@
|
||||
.poiret {
|
||||
font-family: 'Poiret One', sans-serif;
|
||||
}
|
||||
.large {
|
||||
.large {
|
||||
font-size: 200%;
|
||||
}
|
||||
#converse .what, #converse .who {
|
||||
@ -68,8 +68,26 @@
|
||||
</div>
|
||||
<script src="/jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<!--
|
||||
<script src="/gun/lib/cryptomodules.js" type="text/javascript"></script>
|
||||
<script src="/gun/sea.js"></script>
|
||||
-->
|
||||
<script>
|
||||
var gun = Gun(location.origin+'/gun');
|
||||
var user = gun.user && gun.user();
|
||||
if(user){
|
||||
// 1st: call create. 2nd call auth. After that, call recall
|
||||
// user.create('dude', 'my secret').then(function(ack) { console.log('created ack:', ack) });
|
||||
// user.recall().then(function(ack){
|
||||
// if (!ack || !ack.sea){
|
||||
// console.log('user.recall not bootstrapping...');
|
||||
// user.auth('dude', 'my secret', {pin: 'PIN'}).then(function(user) { console.log('authenticated user:', user) });
|
||||
// // user.auth('dude', 'my secret', {pin: 'PIN', newpass: 'my new secret'}).then(function(user) { console.log('authenticated user:', user) });
|
||||
// } else {
|
||||
// console.log('user.recall authenticated user:', ack.alias);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
var chat = gun.get('converse');
|
||||
chat.map().val(function(msg, field){
|
||||
var ul = $('ul'), last = sort(field, ul.children('li').last()), li;
|
||||
|
2
gun.min.js
vendored
2
gun.min.js
vendored
File diff suppressed because one or more lines are too long
9
index.js
9
index.js
@ -1 +1,8 @@
|
||||
module.exports = require('./lib/server');
|
||||
|
||||
const Gun = require('./lib/gunwrapper')
|
||||
const myDir = __dirname // TODO: where did __dirname go ?
|
||||
|
||||
// From here on we're ES6 import compatible...
|
||||
require = require('@std/esm')(module) // eslint-disable-line no-global-assign
|
||||
|
||||
module.exports = require('./lib/server.mjs').default(Gun, myDir)
|
||||
|
46596
lib/cryptography.js
46596
lib/cryptography.js
File diff suppressed because one or more lines are too long
2004
lib/cryptomodules.js
Normal file
2004
lib/cryptomodules.js
Normal file
File diff suppressed because one or more lines are too long
15
lib/gunwrapper.js
Normal file
15
lib/gunwrapper.js
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
// This does all old-fashion require stuff before '@std/mjs' steps in...
|
||||
const Gun = require('../gun')
|
||||
require('../nts')
|
||||
require('./s3')
|
||||
try {
|
||||
require('./ws')
|
||||
} catch(e) {
|
||||
require('./wsp/server')
|
||||
}
|
||||
require('./verify')
|
||||
require('./file')
|
||||
require('./bye')
|
||||
|
||||
module.exports = Gun
|
20
lib/serve.js
20
lib/serve.js
@ -1,20 +0,0 @@
|
||||
module.exports = function serve(req, res, next){
|
||||
if(!req || !res){ return false }
|
||||
next = next || serve;
|
||||
if(!req.url){ return next() }
|
||||
if(0 <= req.url.indexOf('gun.js')){
|
||||
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||
res.end(serve.js = serve.js || require('fs').readFileSync(__dirname + '/../gun.js'));
|
||||
return true;
|
||||
}
|
||||
if(0 <= req.url.indexOf('gun/')){
|
||||
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||
var path = __dirname + '/../' + req.url.split('/').slice(2).join('/'), file;
|
||||
try{file = require('fs').readFileSync(path)}catch(e){}
|
||||
if(file){
|
||||
res.end(file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return next();
|
||||
}
|
41
lib/serve.mjs
Normal file
41
lib/serve.mjs
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
import fs from 'fs'
|
||||
|
||||
let dirname // TODO: where did __dirname go ?
|
||||
|
||||
const serve = (req, res, nxt) => {
|
||||
if (!req || !res) {
|
||||
return false
|
||||
}
|
||||
|
||||
const next = nxt || serve
|
||||
|
||||
if (!req.url) {
|
||||
return next()
|
||||
}
|
||||
|
||||
if (0 <= req.url.indexOf('gun.js')) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(serve.js = serve.js || fs.readFileSync(dirname + '/gun.js'))
|
||||
return true
|
||||
}
|
||||
|
||||
if (0 <= req.url.indexOf('gun/')) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
var path = dirname + '/' + req.url.split('/').slice(2).join('/'), file
|
||||
try {
|
||||
file = fs.readFileSync(path)
|
||||
} catch(e) {} // eslint-disable-line no-empty
|
||||
if (file) {
|
||||
res.end(file)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
export default (dir) => {
|
||||
dirname = dir
|
||||
return serve
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
;(function(){
|
||||
var Gun = require('../gun');
|
||||
Gun.serve = require('./serve');
|
||||
require('../nts');
|
||||
require('./s3');
|
||||
try{require('./ws');}catch(e){require('./wsp/server');}
|
||||
require('./verify');
|
||||
require('./file');
|
||||
require('./bye');
|
||||
module.exports = Gun;
|
||||
}());
|
7
lib/server.mjs
Normal file
7
lib/server.mjs
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
import serve from './serve'
|
||||
|
||||
export default (Gun, dir) => { // TODO: where did __dirname go ?
|
||||
Gun.serve = serve(dir)
|
||||
return Gun
|
||||
}
|
16
package.json
16
package.json
@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"start": "node examples/http.js 8080",
|
||||
"prepublish": "npm run unbuild",
|
||||
"test": "mocha",
|
||||
"test": "mocha && SEA=true mocha",
|
||||
"e2e": "mocha e2e/distributed.js",
|
||||
"docker": "hooks/build",
|
||||
"unbuild": "node lib/unbuild.js && uglifyjs gun.js -o gun.min.js -c -m"
|
||||
@ -44,25 +44,29 @@
|
||||
},
|
||||
"homepage": "https://github.com/amark/gun#readme",
|
||||
"engines": {
|
||||
"node": ">=0.6.6"
|
||||
"node": ">=8.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@std/esm": "^0.8.3",
|
||||
"aws-sdk": ">=2.41.0",
|
||||
"formidable": ">=1.1.1",
|
||||
"spark-md5": "^3.0.0",
|
||||
"ws": "~>2.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"express": ">=4.15.2",
|
||||
"subtle": "^0.1.8",
|
||||
"text-encoding": "^0.6.4",
|
||||
"@trust/webcrypto": "^0.5.0",
|
||||
"buffer": "^5.0.7",
|
||||
"eccrypto": "^1.0.3",
|
||||
"express": ">=4.15.2",
|
||||
"fake-indexeddb": "^2.0.3",
|
||||
"hapi": "^16.1.1",
|
||||
"inert": "^4.2.0",
|
||||
"ip": "^1.1.5",
|
||||
"mocha": ">=3.2.0",
|
||||
"node-localstorage": "^1.3.0",
|
||||
"node-webcrypto-ossl": "^1.0.31",
|
||||
"panic-manager": "^1.2.0",
|
||||
"panic-server": "^1.1.0",
|
||||
"text-encoding": "^0.6.4",
|
||||
"uglify-js": ">=2.8.22",
|
||||
"uws": "~>0.14.1"
|
||||
}
|
||||
|
@ -1,23 +1,33 @@
|
||||
/* global Gun,describe,expect,it */
|
||||
/*eslint max-len: ["error", 95, { "ignoreComments": true }]*/
|
||||
/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}]*/
|
||||
/*eslint object-curly-spacing: ["error", "never"]*/
|
||||
/*eslint node/no-deprecated-api: [error, {ignoreModuleItems: ["new buffer.Buffer()"]}] */
|
||||
var root;
|
||||
(function(env){
|
||||
root = env.window? env.window : global;
|
||||
env.window && root.localStorage && root.localStorage.clear();
|
||||
try{ require('fs').unlinkSync('data.json') }catch(e){}
|
||||
if(!root.sessionStorage){
|
||||
root.sessionStorage = new require('node-localstorage').LocalStorage('.sessionStorage');
|
||||
}
|
||||
root.sessionStorage.clear();
|
||||
if(!root.localStorage){
|
||||
root.localStorage = new require('node-localstorage').LocalStorage('.localStorage');
|
||||
}
|
||||
root.localStorage.clear();
|
||||
try{ require('fs').unlinkSync('data.json') }catch(e){} //eslint-disable-line no-empty
|
||||
//root.Gun = root.Gun || require('../gun');
|
||||
if(root.Gun){
|
||||
root.Gun = root.Gun;
|
||||
if (process.env.SEA && !root.Gun.SEA) {
|
||||
root.Gun.SEA = require('../sea');
|
||||
}
|
||||
} else {
|
||||
root.Gun = require('../gun');
|
||||
Gun.serve = require('../lib/serve');
|
||||
//require('./s3');
|
||||
//require('./uws');
|
||||
//require('./wsp/server');
|
||||
require('../lib/file');
|
||||
root.Gun = require('./index');
|
||||
}
|
||||
}(this));
|
||||
//Gun.log.squelch = true;
|
||||
var gleak = {globals: {}, check: function(){ // via tobyho
|
||||
var leaked = []
|
||||
var leaked = [];
|
||||
for (var key in gleak.globe){ if (!(key in gleak.globals)){ leaked.push(key)} }
|
||||
if (leaked.length > 0){ console.log("GLOBAL LEAK!", leaked); return leaked }
|
||||
}};
|
||||
@ -167,7 +177,7 @@ describe('Performance', function(){ return; // performance tests
|
||||
describe('Gun', function(){
|
||||
var t = {};
|
||||
|
||||
describe('Utility', function(){
|
||||
!Gun.SEA && describe('Utility', function(){
|
||||
var u;
|
||||
/* // causes logger to no longer log.
|
||||
it('verbose console.log debugging', function(done) {
|
||||
@ -1395,7 +1405,7 @@ describe('Gun', function(){
|
||||
});
|
||||
});
|
||||
|
||||
describe('API', function(){
|
||||
!Gun.SEA && describe('API', function(){
|
||||
var gopt = {wire:{put:function(n,cb){cb()},get:function(k,cb){cb()}}};
|
||||
var gun = Gun();
|
||||
|
||||
@ -2982,13 +2992,13 @@ describe('Gun', function(){
|
||||
|
||||
var parent = gun.get('parent');
|
||||
var child = gun.get('child');
|
||||
|
||||
|
||||
child.put({
|
||||
way: 'down'
|
||||
});
|
||||
|
||||
|
||||
parent.get('sub').put(child);
|
||||
|
||||
|
||||
parent.get('sub').on(function(data){
|
||||
//console.log("sub", data);
|
||||
done.sub = data;
|
||||
@ -3018,7 +3028,7 @@ describe('Gun', function(){
|
||||
});
|
||||
|
||||
it('map val get put', function(done){
|
||||
|
||||
|
||||
var gun = Gun().get('chat/asdf');
|
||||
|
||||
var check = {}, count = {};
|
||||
@ -3492,7 +3502,7 @@ describe('Gun', function(){
|
||||
|
||||
var bb = b.get("key");
|
||||
bb.put({msg: "hello"});
|
||||
|
||||
|
||||
d = Gun({file: "ddata"});
|
||||
var db = d.get("key");
|
||||
db.map().on(function(val,field){
|
||||
@ -3534,11 +3544,11 @@ describe('Gun', function(){
|
||||
var gun = Gun();
|
||||
|
||||
gun.get('ds/safe').put({a: 1});
|
||||
|
||||
|
||||
gun.get('ds/safe').on(function(data){
|
||||
data.b = 2;
|
||||
});
|
||||
|
||||
|
||||
gun.get('ds/safe').val(function(data){
|
||||
expect(gun._.root._.graph['ds/safe'].b).to.not.be.ok();
|
||||
if(done.c){ return } done.c = 1;
|
||||
@ -3576,7 +3586,7 @@ describe('Gun', function(){
|
||||
context._.valid = false;
|
||||
chain._.on('in', {get: key, gun: this});
|
||||
return false;
|
||||
} else {
|
||||
} else {
|
||||
_tags = Gun.obj.ify(obj.tags);
|
||||
if(Array.isArray(filter)){
|
||||
context._.valid = filter.every(function(f){ return ( _tags[f] && _tags[f]==1) });
|
||||
|
16
test/index.js
Normal file
16
test/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
// Let's do all old-fashion require stuff before '@std/mjs' steps in...
|
||||
const Gun = require('../gun')
|
||||
|
||||
if (process.env.SEA) {
|
||||
Gun.SEA = require('../sea')
|
||||
}
|
||||
require('../lib/file')
|
||||
|
||||
const myDir = __dirname // TODO: where did __dirname go ?
|
||||
|
||||
// From here on we're ES6 import compatible...
|
||||
require = require('@std/esm')(module) // eslint-disable-line no-global-assign
|
||||
|
||||
module.exports = require('../lib/server.mjs').default(Gun, myDir)
|
542
test/sea.js
542
test/sea.js
@ -1,9 +1,38 @@
|
||||
/* global Gun,describe,expect,it,beforeEach */
|
||||
/*eslint max-len: ["error", 95, { "ignoreComments": true }]*/
|
||||
/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}]*/
|
||||
/*eslint object-curly-spacing: ["error", "never"]*/
|
||||
/*eslint node/no-deprecated-api: [error, {ignoreModuleItems: ["new buffer.Buffer()"]}] */
|
||||
var root;
|
||||
|
||||
(function(env){
|
||||
root = env.window ? env.window : global;
|
||||
}(this));
|
||||
|
||||
if(typeof Buffer === 'undefined'){
|
||||
var Buffer = require('buffer').Buffer;
|
||||
}
|
||||
|
||||
function checkIndexedDB(key, prop, resolve_){
|
||||
var result;
|
||||
Gun.SEA._callonstore_(function(store) {
|
||||
var getData = store.get(key);
|
||||
getData.onsuccess = function(){
|
||||
result = getData.result && getData.result[prop];
|
||||
};
|
||||
}, function(){
|
||||
resolve_(result);
|
||||
});
|
||||
}
|
||||
|
||||
function setIndexedDB(key, prop, resolve_){
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: key, auth: prop});
|
||||
}, function(){
|
||||
resolve_();
|
||||
});
|
||||
}
|
||||
|
||||
Gun.SEA && describe('SEA', function(){
|
||||
console.log('TODO: SEA! THIS IS AN EARLY ALPHA!!!');
|
||||
var alias = 'dude';
|
||||
@ -19,7 +48,7 @@ Gun.SEA && describe('SEA', function(){
|
||||
expect(proof).to.not.be(undefined);
|
||||
expect(proof).to.not.be('');
|
||||
done();
|
||||
}
|
||||
};
|
||||
// proof - generates PBKDF2 hash from user's alias and password
|
||||
// which is then used to decrypt user's auth record
|
||||
if(type === 'callback'){
|
||||
@ -44,17 +73,33 @@ Gun.SEA && describe('SEA', function(){
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.pair(check);
|
||||
} else {
|
||||
Gun.SEA.pair().then(check).catch(done);;
|
||||
Gun.SEA.pair().then(check).catch(done);
|
||||
}
|
||||
});
|
||||
|
||||
it('en', function(done){
|
||||
it('keyid', function(done){
|
||||
Gun.SEA.pair().then(function(key){
|
||||
var check = function(keyid){
|
||||
expect(keyid).to.not.be(undefined);
|
||||
expect(keyid).to.not.be('');
|
||||
expect(keyid.length).to.eql(16);
|
||||
done();
|
||||
};
|
||||
// keyid - creates 8 byte KeyID from public key
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.keyid(key.pub, check);
|
||||
} else {
|
||||
Gun.SEA.keyid(key.pub).then(check);
|
||||
}
|
||||
}).catch(function(e){done(e)});
|
||||
});
|
||||
|
||||
it('enc', function(done){
|
||||
Gun.SEA.pair().then(function(key){
|
||||
var check = function(jsonSecret){
|
||||
expect(jsonSecret).to.not.be(undefined);
|
||||
expect(jsonSecret).to.not.be('');
|
||||
expect(jsonSecret).to.not.eql(clearText);
|
||||
expect(jsonSecret).to.not.eql(JSON.stringify(clearText));
|
||||
var objSecret = JSON.parse(jsonSecret);
|
||||
expect(objSecret).to.have.keys(encKeys);
|
||||
encKeys.map(function(key){
|
||||
@ -65,9 +110,9 @@ Gun.SEA && describe('SEA', function(){
|
||||
};
|
||||
// en - encrypts JSON data using user's private or derived ECDH key
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.en(JSON.stringify(clearText), key.priv, check);
|
||||
Gun.SEA.enc(clearText, key.priv, check);
|
||||
} else {
|
||||
Gun.SEA.en(JSON.stringify(clearText), key.priv).then(check);
|
||||
Gun.SEA.enc(clearText, key.priv).then(check);
|
||||
}
|
||||
}).catch(function(e){done(e)});
|
||||
});
|
||||
@ -82,9 +127,9 @@ Gun.SEA && describe('SEA', function(){
|
||||
};
|
||||
// sign - calculates signature for data using user's private ECDH key
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.sign(key.pub, key.priv, check);
|
||||
Gun.SEA.sign(key.pub, key, check);
|
||||
} else {
|
||||
Gun.SEA.sign(key.pub, key.priv).then(check);
|
||||
Gun.SEA.sign(key.pub, key).then(check);
|
||||
}
|
||||
}).catch(function(e){done(e)});
|
||||
});
|
||||
@ -98,7 +143,7 @@ Gun.SEA && describe('SEA', function(){
|
||||
done();
|
||||
};
|
||||
// sign - calculates signature for data using user's private ECDH key
|
||||
Gun.SEA.sign(key.pub, key.priv).then(function(signature){
|
||||
Gun.SEA.sign(key.pub, key).then(function(signature){
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.verify(key.pub, key.pub, signature, check);
|
||||
} else {
|
||||
@ -108,24 +153,20 @@ Gun.SEA && describe('SEA', function(){
|
||||
}).catch(function(e){done(e)});
|
||||
});
|
||||
|
||||
it('de', function(done){
|
||||
it('dec', function(done){
|
||||
Gun.SEA.pair().then(function(key){
|
||||
var check = function(jsonText){
|
||||
expect(jsonText).to.not.be(undefined);
|
||||
expect(jsonText).to.not.be('');
|
||||
expect(jsonText).to.not.eql(clearText);
|
||||
var decryptedSecret = JSON.parse(jsonText);
|
||||
expect(decryptedSecret).to.not.be(undefined);
|
||||
expect(decryptedSecret).to.not.be('');
|
||||
expect(decryptedSecret).to.be.eql(clearText);
|
||||
var check = function(decText){
|
||||
expect(decText).to.not.be(undefined);
|
||||
expect(decText).to.not.be('');
|
||||
expect(decText).to.be.eql(clearText);
|
||||
done();
|
||||
};
|
||||
Gun.SEA.en(JSON.stringify(clearText), key.priv).then(function(jsonSecret){
|
||||
Gun.SEA.enc(clearText, key.priv).then(function(jsonSecret){
|
||||
// de - decrypts JSON data using user's private or derived ECDH key
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.de(jsonSecret, key.priv, check);
|
||||
Gun.SEA.dec(jsonSecret, key.priv, check);
|
||||
} else {
|
||||
Gun.SEA.de(jsonSecret, key.priv).then(check);
|
||||
Gun.SEA.dec(jsonSecret, key.priv).then(check);
|
||||
}
|
||||
});
|
||||
}).catch(function(e){done(e)});
|
||||
@ -134,7 +175,7 @@ Gun.SEA && describe('SEA', function(){
|
||||
it('derive', function(done){
|
||||
Gun.SEA.pair().then(function(txKey){
|
||||
return Gun.SEA.pair().then(function(rxKey){
|
||||
return { tx: txKey, rx: rxKey };
|
||||
return {tx: txKey, rx: rxKey};
|
||||
});
|
||||
}).then(function(keys){
|
||||
var check = function(shared){
|
||||
@ -149,31 +190,37 @@ Gun.SEA && describe('SEA', function(){
|
||||
// derive - provides shared secret for both receiver and sender
|
||||
// which can be used to encrypt or sign data
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.derive(keys.rx.pub, keys.tx.priv, check);
|
||||
Gun.SEA.derive(keys.rx.pub, keys.tx, check);
|
||||
} else {
|
||||
Gun.SEA.derive(keys.rx.pub, keys.tx.priv).then(check);
|
||||
Gun.SEA.derive(keys.rx.pub, keys.tx).then(check);
|
||||
}
|
||||
}).catch(function(e){done(e)});
|
||||
});
|
||||
|
||||
it('write', function(done){
|
||||
Gun.SEA.pair().then(function(key){
|
||||
Gun.SEA.sign(key.pub, key.priv).then(function(signature){
|
||||
Gun.SEA.sign(key.pub, key).then(function(signature){
|
||||
var check = function(result){
|
||||
expect(result).to.not.be(undefined);
|
||||
expect(result).to.not.be('');
|
||||
expect(result.slice(0, 4)).to.eql('SEA[');
|
||||
var parts = JSON.parse(result.slice(3));
|
||||
expect(parts).to.not.be(undefined);
|
||||
expect(parts[0]).to.be.eql(key.pub);
|
||||
expect(parts[1]).to.be.eql(signature);
|
||||
done();
|
||||
var parts;
|
||||
try{
|
||||
expect(result).to.not.be(undefined);
|
||||
expect(result).to.not.be('');
|
||||
expect(result.slice(0, 4)).to.eql('SEA[');
|
||||
parts = JSON.parse(result.slice(3));
|
||||
expect(parts).to.not.be(undefined);
|
||||
expect(parts[0]).to.be.eql(key.pub);
|
||||
// expect(parts[1]).to.be.eql(signature);
|
||||
}catch(e){ return done(e) }
|
||||
Gun.SEA.verify(key.pub, key.pub, parts[1]).then(function(flag){
|
||||
expect(flag).to.be.true;
|
||||
done();
|
||||
});
|
||||
};
|
||||
// write - wraps data to 'SEA["data","signature"]'
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.write(key.pub, key.priv, check);
|
||||
Gun.SEA.write(key.pub, key, check);
|
||||
} else {
|
||||
Gun.SEA.write(key.pub, key.priv).then(check);
|
||||
Gun.SEA.write(key.pub, key).then(check);
|
||||
}
|
||||
});
|
||||
}).catch(function(e){done(e)});
|
||||
@ -187,8 +234,8 @@ Gun.SEA && describe('SEA', function(){
|
||||
expect(result).to.be.equal(key.pub);
|
||||
done();
|
||||
};
|
||||
Gun.SEA.sign(key.pub, key.priv).then(function(signature){
|
||||
Gun.SEA.write(key.pub, key.priv).then(function(signed){
|
||||
Gun.SEA.sign(key.pub, key).then(function(signature){
|
||||
Gun.SEA.write(key.pub, key).then(function(signed){
|
||||
// read - unwraps data from 'SEA["data","signature"]'
|
||||
if(type === 'callback'){
|
||||
Gun.SEA.read(signed, key.pub, check);
|
||||
@ -223,9 +270,12 @@ Gun().user && describe('Gun', function(){
|
||||
|
||||
if(wipeStorageData){
|
||||
// ... and persisted session
|
||||
localStorage.removeItem('remember')
|
||||
sessionStorage.removeItem('remember');
|
||||
sessionStorage.removeItem('alias');
|
||||
Gun.SEA._callonstore_(function(store) {
|
||||
var act = store.clear(); // Wipes whole IndexedDB
|
||||
act.onsuccess = function(){};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -245,7 +295,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be(undefined);
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.have.keys([ 'ok', 'pub' ]);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
// Gun.user.create - creates new user
|
||||
@ -266,7 +316,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack.err).not.to.be(undefined);
|
||||
expect(ack.err).not.to.be('');
|
||||
expect(ack.err.toLowerCase().indexOf('already created')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
// Gun.user.create - fails to create existing user
|
||||
@ -281,17 +331,29 @@ Gun().user && describe('Gun', function(){
|
||||
});
|
||||
|
||||
describe('auth', function(){
|
||||
var checkStorage = function(done, hasPin){
|
||||
var checkStorage = function(done, notStored){
|
||||
return function(){
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be('');
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be('');
|
||||
if(hasPin){
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be('');
|
||||
var checkValue = function(data, val){
|
||||
if(notStored){
|
||||
expect(typeof data !== 'undefined' && data !== null && data !== '')
|
||||
.to.not.eql(true);
|
||||
} else {
|
||||
expect(data).to.not.be(undefined);
|
||||
expect(data).to.not.be('');
|
||||
if(val){ expect(data).to.eql(val) }
|
||||
}
|
||||
};
|
||||
var alias = root.sessionStorage.getItem('user');
|
||||
checkValue(alias);
|
||||
checkValue(root.sessionStorage.getItem('remember'));
|
||||
if(alias){
|
||||
checkIndexedDB(alias, 'auth', function(auth){
|
||||
checkValue(auth);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
done();
|
||||
};
|
||||
};
|
||||
|
||||
@ -301,7 +363,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be(undefined);
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.key('err');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
// Gun.user.auth - authenticates existing user
|
||||
@ -322,7 +384,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack.err).to.not.be('');
|
||||
expect(ack.err.toLowerCase().indexOf('failed to decrypt secret'))
|
||||
.not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
if(type === 'callback'){
|
||||
@ -343,7 +405,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack.err).to.not.be(undefined);
|
||||
expect(ack.err).to.not.be('');
|
||||
expect(ack.err.toLowerCase().indexOf('no user')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
if(type === 'callback'){
|
||||
@ -361,7 +423,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be(undefined);
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.key('err');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
// Gun.user.auth - with newpass props sets new password
|
||||
@ -383,10 +445,9 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack.err).to.not.be('');
|
||||
expect(ack.err.toLowerCase().indexOf('failed to decrypt secret'))
|
||||
.not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
var props = {alias: alias+type, pass: pass+'not', newpass: pass+' new'};
|
||||
if(type === 'callback'){
|
||||
user.auth(alias+type, pass+'not', check, {newpass: pass+' new'});
|
||||
} else {
|
||||
@ -397,18 +458,32 @@ Gun().user && describe('Gun', function(){
|
||||
}
|
||||
});
|
||||
|
||||
it('without PIN auth session stored to sessionStorage', function(done){
|
||||
it('without PIN auth session stored', function(done){
|
||||
user.auth(alias+type, pass+' new').then(checkStorage(done)).catch(done);
|
||||
});
|
||||
|
||||
it('with PIN auth session stored to sessionStorage', function(done){
|
||||
it('with PIN auth session stored', function(done){
|
||||
if(type === 'callback'){
|
||||
user.auth(alias+type, pass+' new', checkStorage(done, true), {pin: 'PIN'});
|
||||
user.auth(alias+type, pass+' new', checkStorage(done), {pin: 'PIN'});
|
||||
} else {
|
||||
user.auth(alias+type, pass+' new', {pin: 'PIN'})
|
||||
.then(checkStorage(done, true)).catch(done);
|
||||
.then(checkStorage(done)).catch(done);
|
||||
}
|
||||
});
|
||||
|
||||
it('without PIN and zero validity no auth session storing', function(done){
|
||||
user.recall(0).then(function(){
|
||||
user.auth(alias+type, pass+' new')
|
||||
.then(checkStorage(done, true)).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('with PIN and zero validity no auth session storing', function(done){
|
||||
user.recall(0).then(function(){
|
||||
user.auth(alias+type, pass+' new', {pin: 'PIN'})
|
||||
.then(checkStorage(done, true)).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('leave', function(){
|
||||
@ -420,7 +495,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.have.key('err');
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
var usr = alias+type+'leave';
|
||||
@ -434,7 +509,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(usr).to.not.be('');
|
||||
expect(usr).to.not.have.key('err');
|
||||
expect(usr).to.have.key('put');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// Gun.user.leave - performs logout for authenticated user
|
||||
if(type === 'callback'){
|
||||
user.leave(check);
|
||||
@ -452,7 +527,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.key('err');
|
||||
expect(ack).to.have.key('ok');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
@ -483,7 +558,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.have.key('err');
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
};
|
||||
@ -496,7 +571,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.key('err');
|
||||
expect(ack).to.have.key('put');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// Gun.user.delete - deletes existing user account
|
||||
if(type === 'callback'){
|
||||
user.delete(usr, pass, check(done));
|
||||
@ -526,7 +601,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.have.key('put');
|
||||
expect(ack).to.have.key('err');
|
||||
expect(ack.err.toLowerCase().indexOf('no user')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
if(type === 'callback'){
|
||||
@ -539,7 +614,7 @@ Gun().user && describe('Gun', function(){
|
||||
});
|
||||
});
|
||||
|
||||
describe('recall', function(){
|
||||
describe('recall (from IndexedDB)', function(){
|
||||
var doCheck = function(done, hasPin, wantAck){
|
||||
expect(typeof done).to.be('function');
|
||||
return function(ack){
|
||||
@ -549,69 +624,84 @@ Gun().user && describe('Gun', function(){
|
||||
expect(user).to.not.be('');
|
||||
expect(sRemember).to.not.be(undefined);
|
||||
expect(sRemember).to.not.be('');
|
||||
if(hasPin){
|
||||
var lRemember = root.localStorage.getItem('remember');
|
||||
expect(lRemember).to.not.be(undefined);
|
||||
expect(lRemember).to.not.be('');
|
||||
}
|
||||
// NOTE: done can be Promise returning function
|
||||
|
||||
var ret;
|
||||
if (wantAck) {
|
||||
[ 'err', 'pub', 'sea', 'alias', 'put' ].forEach(function(key){
|
||||
if(wantAck && ack){
|
||||
['err', 'pub', 'sea', 'alias', 'put'].forEach(function(key){
|
||||
if(typeof ack[key] !== 'undefined'){
|
||||
(ret = ret || {})[key] = ack[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
return done(ret);
|
||||
// NOTE: done can be Promise returning function
|
||||
return !hasPin || !wantAck || !ack ? done(ret)
|
||||
: new Promise(function(resolve){
|
||||
checkIndexedDB(ack.alias, 'auth', function(auth){
|
||||
expect(auth).to.not.be(undefined);
|
||||
expect(auth).to.not.be('');
|
||||
resolve(done(wantAck && Object.assign(ret || {}, {auth: auth})));
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
// This re-constructs 'remember-me' data modified by manipulate func
|
||||
var manipulateStorage = function(manipulate, hasPin){
|
||||
var manipulateStorage = function(manipulate, pin){
|
||||
expect(typeof manipulate).to.be('function');
|
||||
// We'll use Gun internal User data
|
||||
var usr = gun.back(-1)._.user;
|
||||
expect(usr).to.not.be(undefined);
|
||||
expect(usr).to.have.key('_');
|
||||
expect(usr._).to.have.keys([ 'pub', 'sea' ]);
|
||||
expect(usr._).to.have.keys(['pub', 'sea']);
|
||||
// ... to validate 'remember' data
|
||||
var remember = hasPin ? localStorage.getItem('remember')
|
||||
: sessionStorage.getItem('remember');
|
||||
return Gun.SEA.read(remember, usr._.pub).then(function(props){
|
||||
try{ props && (props = JSON.parse(props)) }catch(e){}
|
||||
pin = pin && new Buffer(pin, 'utf8').toString('base64');
|
||||
return !pin ? Promise.resolve(sessionStorage.getItem('remember'))
|
||||
: new Promise(function(resolve){
|
||||
checkIndexedDB(usr._.alias, 'auth', resolve);
|
||||
}).then(function(remember){
|
||||
return Gun.SEA.read(remember, usr._.pub).then(function(props){
|
||||
return !pin ? props
|
||||
: Gun.SEA.dec(props, pin);
|
||||
});
|
||||
}).then(function(props){
|
||||
try{ props && (props = JSON.parse(props)) }catch(e){} //eslint-disable-line no-empty
|
||||
return props;
|
||||
}).then(manipulate).then(function(props){
|
||||
expect(props).to.not.be(undefined);
|
||||
expect(props).to.not.be('');
|
||||
return Gun.SEA.write(JSON.stringify(props), usr._.sea)
|
||||
var keys = {pub: usr._.pub, priv: usr._.sea.priv};
|
||||
return Gun.SEA.write(JSON.stringify(props), keys)
|
||||
.then(function(remember){
|
||||
return hasPin ? sessionStorage.setItem('remember', remember)
|
||||
: sessionStorage.setItem('remember', remember);
|
||||
return !pin ? sessionStorage.setItem('remember', remember)
|
||||
: Gun.SEA.enc(remember, pin).then(function(encauth){
|
||||
return new Promise(function(resolve){
|
||||
setIndexedDB(usr._.alias, encauth, resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
it('with PIN auth session stored to localStorage', function(done){
|
||||
it('with PIN auth session stores', function(done){
|
||||
var doAction = function(){
|
||||
user.auth(alias+type, pass+' new', { pin: 'PIN' })
|
||||
user.auth(alias+type, pass+' new', {pin: 'PIN'})
|
||||
.then(doCheck(done, true)).catch(done);
|
||||
};
|
||||
if(type === 'callback'){
|
||||
user.recall(doAction, { session: false });
|
||||
user.recall(doAction);
|
||||
} else {
|
||||
user.recall({ session: false }).then(doAction).catch(done)
|
||||
user.recall().then(doAction).catch(done);
|
||||
}
|
||||
});
|
||||
|
||||
it('without PIN auth session stored to sessionStorage', function(done){
|
||||
it('without PIN auth session stores', function(done){
|
||||
var doAction = function(){
|
||||
user.auth(alias+type, pass+' new').then(doCheck(done));
|
||||
};
|
||||
user.leave().then(function(){
|
||||
if(type === 'callback'){
|
||||
user.recall(doAction, { session: false });
|
||||
user.recall(doAction);
|
||||
} else {
|
||||
user.recall({ session: false }).then(doAction).catch(done)
|
||||
user.recall().then(doAction).catch(done);
|
||||
}
|
||||
}).catch(done);
|
||||
});
|
||||
@ -627,19 +717,19 @@ Gun().user && describe('Gun', function(){
|
||||
}
|
||||
});
|
||||
|
||||
it('validity but no PIN stored to sessionStorage', function(done){
|
||||
it('with validity but no PIN stores using random PIN', function(done){
|
||||
var doAction = function(){
|
||||
user.auth(alias+type, pass+' new').then(doCheck(done)).catch(done);
|
||||
};
|
||||
if(type === 'callback'){
|
||||
user.recall(12 * 60, doAction, {session: false});
|
||||
user.recall(12 * 60, doAction);
|
||||
} else {
|
||||
user.recall(12 * 60, {session: false}).then(doAction)
|
||||
user.recall(12 * 60).then(doAction)
|
||||
.catch(done);
|
||||
}
|
||||
});
|
||||
|
||||
it('valid sessionStorage session', function(done){
|
||||
it('validity and auth with PIN but storage empty', function(done){
|
||||
user.auth(alias+type, pass+' new').then(function(usr){
|
||||
var sUser;
|
||||
var sRemember;
|
||||
@ -648,35 +738,45 @@ Gun().user && describe('Gun', function(){
|
||||
expect(usr).to.not.be('');
|
||||
expect(usr).to.not.have.key('err');
|
||||
expect(usr).to.have.key('put');
|
||||
expect(root.sessionStorage.getItem('user')).to.be(alias+type);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be('');
|
||||
|
||||
sUser = root.sessionStorage.getItem('user');
|
||||
expect(sUser).to.be(alias+type);
|
||||
|
||||
sRemember = root.sessionStorage.getItem('remember');
|
||||
}catch(e){ done(e); return };
|
||||
expect(sRemember).to.not.be(undefined);
|
||||
expect(sRemember).to.not.be('');
|
||||
}catch(e){ done(e); return }
|
||||
user.leave().then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(sUser);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(sRemember);
|
||||
}catch(e){ done(e); return };
|
||||
|
||||
}catch(e){ done(e); return }
|
||||
// Restore but leave IndexedDB empty
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
|
||||
user.recall(12 * 60, {session: false}).then(doCheck(done))
|
||||
user.recall(12 * 60).then(
|
||||
doCheck(function(ack){
|
||||
expect(ack).to.have.key('err');
|
||||
expect(ack.err.toLowerCase().indexOf('no authentication')).to.not.be(-1);
|
||||
checkIndexedDB(alias+type, 'auth', function(auth){
|
||||
expect((typeof auth !== 'undefined' && auth !== null && auth !== ''))
|
||||
.to.not.eql(true);
|
||||
done();
|
||||
});
|
||||
}, false, true))
|
||||
.catch(done);
|
||||
}).catch(done);
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('valid localStorage session bootstrap', function(done){
|
||||
user.auth(alias+type, pass+' new', { pin: 'PIN' }).then(function(usr){
|
||||
var sUser;
|
||||
var sRemember;
|
||||
var lRemember;
|
||||
it('valid session bootstrap', function(done){
|
||||
var sUser;
|
||||
var sRemember;
|
||||
var iAuth;
|
||||
user.auth(alias+type, pass+' new', {pin: 'PIN'}).then(function(usr){
|
||||
try{
|
||||
expect(usr).to.not.be(undefined);
|
||||
expect(usr).to.not.be('');
|
||||
@ -685,56 +785,77 @@ Gun().user && describe('Gun', function(){
|
||||
expect(root.sessionStorage.getItem('user')).to.be(alias+type);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be('');
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be('');
|
||||
|
||||
sUser = root.sessionStorage.getItem('user');
|
||||
sRemember = root.sessionStorage.getItem('remember');
|
||||
lRemember = root.localStorage.getItem('remember');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
|
||||
user.leave().then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(sUser);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(sRemember);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(lRemember);
|
||||
}catch(e){ done(e); return };
|
||||
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
root.localStorage.setItem('remember', lRemember);
|
||||
|
||||
user.recall(12 * 60, {session: false}).then(doCheck(done))
|
||||
.catch(done);
|
||||
}).catch(done);
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('valid localStorage session bootstraps using PIN', function(done){
|
||||
user.recall(12 * 60, {session: false}).then(function(){
|
||||
return user.auth(alias+type, pass+' new', { pin: 'PIN' });
|
||||
}).then(doCheck(function(){
|
||||
// Let's save remember props
|
||||
var sUser = root.sessionStorage.getItem('user');
|
||||
var sRemember = root.sessionStorage.getItem('remember');
|
||||
var lRemember = root.localStorage.getItem('remember');
|
||||
// Then logout user
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){ resolve(iAuth = auth) });
|
||||
});
|
||||
}).then(function(){
|
||||
return user.leave().then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(sUser);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(sRemember);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(lRemember);
|
||||
}catch(e){ done(e); return };
|
||||
// Then restore localStorage remember data, skip sessionStorage
|
||||
root.localStorage.setItem('remember', lRemember);
|
||||
}catch(e){ done(e); return }
|
||||
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
expect(auth).to.not.be(iAuth);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}).then(function(){
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
|
||||
return new Promise(function(resolve){
|
||||
setIndexedDB(sUser, iAuth, resolve);
|
||||
});
|
||||
}).then(function(){
|
||||
user.recall(12 * 60).then(doCheck(done))
|
||||
.catch(done);
|
||||
}).catch(done);
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('valid session bootstrap using alias & PIN', function(done){
|
||||
user.recall(12 * 60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: 'PIN'});
|
||||
}).then(doCheck(function(ack){
|
||||
// Let's save remember props
|
||||
var sUser = root.sessionStorage.getItem('user');
|
||||
var sRemember = root.sessionStorage.getItem('remember');
|
||||
var iAuth = ack.auth;
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
iAuth = auth;
|
||||
resolve(user.leave()); // Then logout user
|
||||
});
|
||||
}).then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(sUser);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(sRemember);
|
||||
}catch(e){ done(e); return }
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
try{ expect(auth).to.not.be(iAuth) }catch(e){ done(e) }
|
||||
// Then restore IndexedDB but skip sessionStorage remember
|
||||
setIndexedDB(sUser, iAuth, function(){
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
resolve(ack);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, true)).then(function(){
|
||||
}, true, true)).then(function(){
|
||||
// Then try to recall authentication
|
||||
return user.recall(12 * 60, {session: false}).then(function(props){
|
||||
return user.recall(12 * 60).then(function(props){
|
||||
try{
|
||||
expect(props).to.not.be(undefined);
|
||||
expect(props).to.not.be('');
|
||||
@ -742,9 +863,9 @@ Gun().user && describe('Gun', function(){
|
||||
// Which fails to missing PIN
|
||||
expect(props.err.toLowerCase()
|
||||
.indexOf('missing pin')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// Ok, time to try auth with alias & PIN
|
||||
return user.auth(alias+type, undefined, { pin: 'PIN' });
|
||||
return user.auth(alias+type, undefined, {pin: 'PIN'});
|
||||
});
|
||||
}).then(doCheck(function(usr){
|
||||
try{
|
||||
@ -752,33 +873,46 @@ Gun().user && describe('Gun', function(){
|
||||
expect(usr).to.not.be('');
|
||||
expect(usr).to.not.have.key('err');
|
||||
expect(usr).to.have.key('put');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// We've recalled authenticated session using alias & PIN!
|
||||
done();
|
||||
}, true, true)).catch(done);
|
||||
});
|
||||
|
||||
it('valid localStorage session fails to bootstrap using wrong PIN',
|
||||
it('valid session fails to bootstrap with alias & wrong PIN',
|
||||
function(done){
|
||||
user.recall(12 * 60, {session: false}).then(function(){
|
||||
return user.auth(alias+type, pass+' new', { pin: 'PIN' });
|
||||
}).then(doCheck(function(){
|
||||
user.recall(12 * 60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: 'PIN'});
|
||||
}).then(doCheck(function(ack){
|
||||
var sUser = root.sessionStorage.getItem('user');
|
||||
var sRemember = root.sessionStorage.getItem('remember');
|
||||
var lRemember = root.localStorage.getItem('remember');
|
||||
return user.leave().then(function(ack){
|
||||
var iAuth = ack.auth;
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
iAuth = auth;
|
||||
resolve(user.leave()); // Then logout user
|
||||
});
|
||||
}).then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
expect(gun.back(-1)._.user).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(root.sessionStorage.getItem('user')).to.not.be(sUser);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(sRemember);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(lRemember);
|
||||
}catch(e){ done(e); return };
|
||||
root.localStorage.setItem('remember', lRemember);
|
||||
}catch(e){ done(e); return }
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
try{ expect(auth).to.not.be(iAuth) }catch(e){ done(e) }
|
||||
// Then restore IndexedDB auth data, skip sessionStorage
|
||||
setIndexedDB(sUser, iAuth, function(){
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
resolve(ack);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, true)).then(function(){
|
||||
}, true, true)).then(function(){
|
||||
// Ok, time to try auth with alias & PIN
|
||||
return user.auth(alias+type, undefined, { pin: 'PiN' });
|
||||
return user.auth(alias+type, undefined, {pin: 'PiN'});
|
||||
}).then(function(){
|
||||
done('Unexpected login success!');
|
||||
}).catch(function(ack){
|
||||
@ -788,25 +922,26 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.have.key('err');
|
||||
expect(ack.err.toLowerCase()
|
||||
.indexOf('no session data for alias & pin')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// We've recalled authenticated session using alias & PIN!
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('expired session fails to bootstrap', function(done){
|
||||
user.recall(60, {session: true}).then(function(){
|
||||
return user.auth(alias+type, pass+' new');
|
||||
var pin = 'PIN';
|
||||
user.recall(60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: pin});
|
||||
}).then(doCheck(function(){
|
||||
// Storage data OK, let's back up time of auth to exp + 65 seconds
|
||||
return manipulateStorage(function(props){
|
||||
var ret = Object.assign({}, props, { iat: props.iat - 65 - props.exp });
|
||||
var ret = Object.assign({}, props, {iat: props.iat - 65 - props.exp});
|
||||
return ret;
|
||||
}, false);
|
||||
}, pin);
|
||||
})).then(function(){
|
||||
// Simulate browser reload
|
||||
throwOutUser();
|
||||
user.recall(60, {session: true}).then(function(ack){
|
||||
user.recall(60).then(function(ack){
|
||||
expect(ack).to.not.be(undefined);
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.keys([ 'pub', 'sea' ]);
|
||||
@ -821,51 +956,54 @@ Gun().user && describe('Gun', function(){
|
||||
});
|
||||
|
||||
it('changed password', function(done){
|
||||
user.recall(60, {session: false}).then(function(){
|
||||
return user.auth(alias+type, pass+' new', { pin: 'PIN' });
|
||||
var pin = 'PIN';
|
||||
var sUser;
|
||||
var sRemember;
|
||||
var iAuth;
|
||||
user.recall(60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: pin});
|
||||
}).then(function(usr){
|
||||
var sUser;
|
||||
var sRemember;
|
||||
var lRemember;
|
||||
try{
|
||||
expect(usr).to.not.be(undefined);
|
||||
expect(usr).to.not.be('');
|
||||
expect(usr).to.not.have.key('err');
|
||||
expect(usr).to.have.key('put');
|
||||
expect(root.sessionStorage.getItem('user')).to.be(alias+type);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be('');
|
||||
expect(root.localStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.localStorage.getItem('remember')).to.not.be('');
|
||||
|
||||
sUser = root.sessionStorage.getItem('user');
|
||||
sRemember = root.sessionStorage.getItem('remember');
|
||||
lRemember = root.localStorage.getItem('remember');
|
||||
}catch(e){ done(e); return };
|
||||
// Time to do new login with new password set
|
||||
user.leave().then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
}catch(e){ done(e); return };
|
||||
expect(sUser).to.be(alias+type);
|
||||
|
||||
return user.auth(alias+type, pass+' new', {newpass: pass, pin: 'PIN' }).then(function(usr){
|
||||
expect(usr).to.not.have.key('err');
|
||||
});
|
||||
sRemember = root.sessionStorage.getItem('remember');
|
||||
expect(sRemember).to.not.be(undefined);
|
||||
expect(sRemember).to.not.be('');
|
||||
}catch(e){ done(e); return }
|
||||
|
||||
return new Promise(function(resolve){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){ resolve(iAuth = auth) });
|
||||
});
|
||||
}).then(function(){
|
||||
return user.leave().then(function(ack){
|
||||
try{ expect(ack).to.have.key('ok') }catch(e){ done(e); return }
|
||||
|
||||
return user.auth(alias+type, pass+' new', {newpass: pass, pin: pin})
|
||||
.then(function(usr){ expect(usr).to.not.have.key('err') });
|
||||
}).then(function(){
|
||||
return user.leave().then(function(ack){
|
||||
try{
|
||||
expect(ack).to.have.key('ok');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
throwOutUser();
|
||||
});
|
||||
}).then(function(){
|
||||
// Simulate browser reload
|
||||
// Call back previous remember data
|
||||
// Call back pre-update remember...
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
root.localStorage.setItem('remember', lRemember);
|
||||
|
||||
user.recall(60, {session: false}).then(function(props){
|
||||
// ... and IndexedDB auth
|
||||
return new Promise(function(resolve){
|
||||
setIndexedDB(sUser, iAuth, resolve);
|
||||
});
|
||||
}).then(function(){
|
||||
user.recall(60).then(function(props){
|
||||
expect(props).to.not.be(undefined);
|
||||
expect(props).to.not.be('');
|
||||
expect(props).to.have.key('err');
|
||||
@ -880,24 +1018,24 @@ Gun().user && describe('Gun', function(){
|
||||
});
|
||||
|
||||
it('recall hook session manipulation', function(done){
|
||||
var pin = 'PIN';
|
||||
var exp;
|
||||
var hookFunc = function(props){
|
||||
exp = props.exp * 2;
|
||||
var ret = Object.assign({}, props, { exp: exp });
|
||||
exp = props.exp * 2; // Doubles session expiration time
|
||||
var ret = Object.assign({}, props, {exp: exp});
|
||||
return (type === 'callback' && ret) || new Promise(function(resolve){
|
||||
resolve(ret);
|
||||
resolve(ret); // Both callback & Promise methods here
|
||||
});
|
||||
};
|
||||
user.recall(60, { session: true, hook: hookFunc }).then(function(){
|
||||
return user.auth(alias+type, pass);
|
||||
user.recall(60, {hook: hookFunc}).then(function(){
|
||||
return user.auth(alias+type, pass, {pin: pin});
|
||||
}).then(function(){
|
||||
// Storage data OK, let's back up time of auth 65 minutes
|
||||
return manipulateStorage(function(props){
|
||||
expect(props).to.not.be(undefined);
|
||||
expect(props).to.have.key('exp');
|
||||
expect(props.exp).to.be(exp);
|
||||
return props;
|
||||
}, false);
|
||||
}, pin);
|
||||
}).then(done).catch(done);
|
||||
});
|
||||
});
|
||||
@ -910,7 +1048,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.not.have.key('err');
|
||||
expect(ack).to.have.keys([ 'sea', 'pub' ]);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
var aliveUser = alias+type+'alive';
|
||||
@ -918,13 +1056,13 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.be(undefined);
|
||||
expect(ack).to.not.be('');
|
||||
expect(ack).to.have.keys([ 'ok', 'pub' ]);
|
||||
user.auth(aliveUser, pass, { pin: 'PIN' }).then(function(usr){
|
||||
user.auth(aliveUser, pass, {pin: 'PIN'}).then(function(usr){
|
||||
try{
|
||||
expect(usr).to.not.be(undefined);
|
||||
expect(usr).to.not.be('');
|
||||
expect(usr).to.not.have.key('err');
|
||||
expect(usr).to.have.key('put');
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
// Gun.user.alive - keeps/checks User authentiation state
|
||||
if(type === 'callback'){
|
||||
user.alive(check);
|
||||
@ -943,7 +1081,7 @@ Gun().user && describe('Gun', function(){
|
||||
expect(ack).to.not.have.keys([ 'sea', 'pub' ]);
|
||||
expect(ack).to.have.key('err');
|
||||
expect(ack.err.toLowerCase().indexOf('no session')).not.to.be(-1);
|
||||
}catch(e){ done(e); return };
|
||||
}catch(e){ done(e); return }
|
||||
done();
|
||||
};
|
||||
user.leave().catch(function(){}).then(function(){
|
||||
|
Loading…
x
Reference in New Issue
Block a user