mirror of
https://github.com/amark/gun.git
synced 2025-06-06 14:16:44 +00:00
Removed 'session' to fulfill three step remember-me spec
This commit is contained in:
parent
d32eaf833e
commit
9157b0de6b
37
sea.js
37
sea.js
@ -52,14 +52,12 @@
|
||||
|
||||
var _initial_authsettings = {
|
||||
validity: 12 * 60 * 60, // internally in seconds : 12 hours
|
||||
session: true,
|
||||
hook: function(props){ return props } // { iat, exp, alias, remember }
|
||||
// or return new Promise(function(resolve, reject){(resolve(props))})
|
||||
};
|
||||
// These are used to persist user's authentication "session"
|
||||
var authsettings = {
|
||||
validity: _initial_authsettings.validity,
|
||||
session: _initial_authsettings.session,
|
||||
hook: _initial_authsettings.hook
|
||||
};
|
||||
|
||||
@ -178,12 +176,12 @@
|
||||
return function(props){
|
||||
return new Promise(function(resolve, reject){
|
||||
if(!Gun.obj.has(props, 'alias')){ return resolve() }
|
||||
if(proof && Gun.obj.has(props, 'iat')){
|
||||
if(authsettings.validity && proof && Gun.obj.has(props, 'iat')){
|
||||
props.proof = proof;
|
||||
delete props.remember; // Not stored if present
|
||||
|
||||
var remember = (pin && {alias: props.alias, pin: pin}) || props;
|
||||
var persist = !authsettings.session && pin && props;
|
||||
var remember = {alias: props.alias, pin: pin};
|
||||
var persist = props;
|
||||
|
||||
return SEA.write(JSON.stringify(remember), priv).then(function(signed){
|
||||
sessionStorage.setItem('user', props.alias);
|
||||
@ -209,6 +207,7 @@
|
||||
}).then(function(){ resolve(props) })
|
||||
.catch(function(e){ reject({err: 'Session persisting failed!'}) });
|
||||
}
|
||||
// TODO: remove IndexedDB when using random PIN
|
||||
return new Promise(function(resolve){
|
||||
SEA._callonstore_(function(store) {
|
||||
var act = store.clear(); // Wipes whole IndexedDB
|
||||
@ -226,14 +225,13 @@
|
||||
// This internal func persists User authentication if so configured
|
||||
function authpersist(user,proof,opts){
|
||||
// opts = { pin: 'string' }
|
||||
// authsettings.session = true // disables PIN method
|
||||
// TODO: how this works:
|
||||
// no opts.pin then uses random PIN
|
||||
// How this works:
|
||||
// called when app bootstraps, with wanted options
|
||||
// IF authsettings.validity === 0 THEN no remember-me, ever
|
||||
// IF authsettings.session === true THEN no window.indexedDB in use; nor PIN
|
||||
// ELSE if no PIN then window.sessionStorage
|
||||
var pin = Gun.obj.has(opts, 'pin') && opts.pin
|
||||
&& new Buffer(opts.pin, 'utf8').toString('base64');
|
||||
// IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB
|
||||
var pin = (Gun.obj.has(opts, 'pin') && opts.pin) || Gun.text.random(10);
|
||||
pin = new Buffer(pin, 'utf8').toString('base64');
|
||||
|
||||
if(proof && user && user.alias && authsettings.validity){
|
||||
var args = {alias: user.alias};
|
||||
@ -253,7 +251,7 @@
|
||||
// This internal func recalls persisted User authentication if so configured
|
||||
function authrecall(root,authprops){
|
||||
return new Promise(function(resolve, reject){
|
||||
// TODO: sessionStorage to only hold signed { alias, pin } !!!
|
||||
// window.sessionStorage only holds signed { alias, pin } !!!
|
||||
var remember = authprops || sessionStorage.getItem('remember');
|
||||
var alias = Gun.obj.has(authprops, 'alias') && authprops.alias
|
||||
|| sessionStorage.getItem('user');
|
||||
@ -375,7 +373,7 @@
|
||||
};
|
||||
}, function(){ // And return proof if for matching alias
|
||||
reject({
|
||||
err: (gotRemember && 'Missing PIN and alias!')
|
||||
err: (gotRemember && authsettings.validity && 'Missing PIN and alias!')
|
||||
|| 'No authentication session found!'});
|
||||
});
|
||||
});
|
||||
@ -498,8 +496,6 @@
|
||||
cb = typeof cb === 'function' && cb;
|
||||
|
||||
var doIt = function(resolve, reject){
|
||||
// TODO: !pass && opt.pin => try to recall
|
||||
// return reject({err: 'Auth attempt failed! Reason: No session data for alias & PIN'});
|
||||
if(!pass && Gun.obj.has(opts, 'pin')){
|
||||
return authrecall(root, {alias: alias, pin: opts.pin}).then(function(props){
|
||||
resolve(props);
|
||||
@ -624,17 +620,14 @@
|
||||
|
||||
var doIt = function(resolve, reject){
|
||||
// opts = { hook: function({ iat, exp, alias, proof }),
|
||||
// session: false } // true disables PIN requirement/support
|
||||
// session: false } // true uses random PIN, no PIN UX error generated
|
||||
// iat == Date.now() when issued, exp == seconds to expire from iat
|
||||
// TODO: how this works:
|
||||
// How this works:
|
||||
// called when app bootstraps, with wanted options
|
||||
// IF validity === 0 THEN no remember-me, ever
|
||||
// IF opt.session === true THEN no window.indexedDB in use; nor PIN
|
||||
// IF authsettings.validity === 0 THEN no remember-me, ever
|
||||
// IF PIN then signed 'remember' to window.sessionStorage and 'auth' to IndexedDB
|
||||
authsettings.validity = typeof validity !== 'undefined' ? validity
|
||||
: _initial_authsettings.validity;
|
||||
if(Gun.obj.has(opts, 'session')){
|
||||
authsettings.session = opts.session;
|
||||
}
|
||||
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?
|
||||
|
127
test/sea.js
127
test/sea.js
@ -25,6 +25,14 @@ function checkIndexedDB(key, prop, resolve_){
|
||||
});
|
||||
}
|
||||
|
||||
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';
|
||||
@ -300,22 +308,30 @@ Gun().user && describe('Gun', function(){
|
||||
});
|
||||
|
||||
describe('auth', function(){
|
||||
var checkStorage = function(done, hasPin){
|
||||
var checkStorage = function(done, notStored){
|
||||
return function(){
|
||||
var checkValue = function(data, val){
|
||||
if(notStored){
|
||||
if(typeof data !== 'undefined' && data !== null && data !== ''){
|
||||
expect(data).to.not.be(undefined);
|
||||
}
|
||||
} 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');
|
||||
expect(alias).to.not.be(undefined);
|
||||
expect(alias).to.not.be('');
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be(undefined);
|
||||
expect(root.sessionStorage.getItem('remember')).to.not.be('');
|
||||
|
||||
if(!hasPin){
|
||||
return done();
|
||||
}
|
||||
checkIndexedDB(alias, 'auth', function(auth){
|
||||
expect(auth).to.not.be(undefined);
|
||||
expect(auth).to.not.be('');
|
||||
checkValue(alias);
|
||||
checkValue(root.sessionStorage.getItem('remember'));
|
||||
if(alias){
|
||||
checkIndexedDB(alias, 'auth', function(auth){
|
||||
checkValue(auth);
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -420,18 +436,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(){
|
||||
@ -621,9 +651,7 @@ Gun().user && describe('Gun', function(){
|
||||
return !pin ? sessionStorage.setItem('remember', remember)
|
||||
: Gun.SEA.enc(remember, pin).then(function(encauth){
|
||||
return new Promise(function(resolve){
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: usr._.alias, auth: encauth});
|
||||
}, resolve);
|
||||
setIndexedDB(usr._.alias, encauth, resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -636,21 +664,21 @@ Gun().user && describe('Gun', function(){
|
||||
.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 stored to IndexedDB', 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);
|
||||
});
|
||||
@ -666,14 +694,14 @@ Gun().user && describe('Gun', function(){
|
||||
}
|
||||
});
|
||||
|
||||
it('validity but no PIN stored to sessionStorage', function(done){
|
||||
it('validity but no PIN stored to IndexedDB 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);
|
||||
}
|
||||
});
|
||||
@ -687,12 +715,13 @@ 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');
|
||||
expect(sRemember).to.not.be(undefined);
|
||||
expect(sRemember).to.not.be('');
|
||||
}catch(e){ done(e); return }
|
||||
user.leave().then(function(ack){
|
||||
try{
|
||||
@ -705,7 +734,7 @@ Gun().user && describe('Gun', function(){
|
||||
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(done))
|
||||
.catch(done);
|
||||
}).catch(done);
|
||||
}).catch(done);
|
||||
@ -752,19 +781,17 @@ Gun().user && describe('Gun', function(){
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
|
||||
return new Promise(function(resolve){
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: sUser, auth: iAuth});
|
||||
}, resolve);
|
||||
setIndexedDB(sUser, iAuth, resolve);
|
||||
});
|
||||
}).then(function(){
|
||||
user.recall(12 * 60, {session: false}).then(doCheck(done))
|
||||
user.recall(12 * 60).then(doCheck(done))
|
||||
.catch(done);
|
||||
}).catch(done);
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('valid IndexedDB session bootstraps using PIN', function(done){
|
||||
user.recall(12 * 60, {session: false}).then(function(){
|
||||
user.recall(12 * 60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: 'PIN'});
|
||||
}).then(doCheck(function(ack){
|
||||
// Let's save remember props
|
||||
@ -787,9 +814,7 @@ Gun().user && describe('Gun', function(){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
try{ expect(auth).to.not.be(iAuth) }catch(e){ done(e) }
|
||||
// Then restore IndexedDB auth data, skip sessionStorage
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: sUser, auth: iAuth});
|
||||
}, function(){
|
||||
setIndexedDB(sUser, iAuth, function(){
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
resolve(ack);
|
||||
});
|
||||
@ -798,7 +823,7 @@ Gun().user && describe('Gun', 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('');
|
||||
@ -824,7 +849,7 @@ Gun().user && describe('Gun', function(){
|
||||
|
||||
it('valid IndexedDB session fails to bootstrap using wrong PIN',
|
||||
function(done){
|
||||
user.recall(12 * 60, {session: false}).then(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');
|
||||
@ -846,9 +871,7 @@ Gun().user && describe('Gun', function(){
|
||||
checkIndexedDB(sUser, 'auth', function(auth){
|
||||
try{ expect(auth).to.not.be(iAuth) }catch(e){ done(e) }
|
||||
// Then restore IndexedDB auth data, skip sessionStorage
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: sUser, auth: iAuth});
|
||||
}, function(){
|
||||
setIndexedDB(sUser, iAuth, function(){
|
||||
root.sessionStorage.setItem('user', sUser);
|
||||
resolve(ack);
|
||||
});
|
||||
@ -875,7 +898,7 @@ Gun().user && describe('Gun', function(){
|
||||
|
||||
it('expired session fails to bootstrap', function(done){
|
||||
var pin = 'PIN';
|
||||
user.recall(60, {session: false}).then(function(){
|
||||
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
|
||||
@ -886,7 +909,7 @@ Gun().user && describe('Gun', function(){
|
||||
})).then(function(){
|
||||
// Simulate browser reload
|
||||
throwOutUser();
|
||||
user.recall(60, {session: false}).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' ]);
|
||||
@ -905,7 +928,7 @@ Gun().user && describe('Gun', function(){
|
||||
var sUser;
|
||||
var sRemember;
|
||||
var iAuth;
|
||||
user.recall(60, {session: false}).then(function(){
|
||||
user.recall(60).then(function(){
|
||||
return user.auth(alias+type, pass+' new', {pin: pin});
|
||||
}).then(function(usr){
|
||||
try{
|
||||
@ -945,12 +968,10 @@ Gun().user && describe('Gun', function(){
|
||||
root.sessionStorage.setItem('remember', sRemember);
|
||||
|
||||
return new Promise(function(resolve){
|
||||
Gun.SEA._callonstore_(function(store){
|
||||
store.put({id: sUser, auth: iAuth});
|
||||
}, resolve);
|
||||
setIndexedDB(sUser, iAuth, resolve);
|
||||
});
|
||||
}).then(function(){
|
||||
user.recall(60, {session: false}).then(function(props){
|
||||
user.recall(60).then(function(props){
|
||||
expect(props).to.not.be(undefined);
|
||||
expect(props).to.not.be('');
|
||||
expect(props).to.have.key('err');
|
||||
@ -974,7 +995,7 @@ Gun().user && describe('Gun', function(){
|
||||
resolve(ret);
|
||||
});
|
||||
};
|
||||
user.recall(60, {session: false, hook: hookFunc}).then(function(){
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user