Almost completed Gun.user test cases - remember is still TODO:

This commit is contained in:
mhelander 2017-08-29 19:49:08 +03:00
parent 50b69db8d5
commit 09db7fd9d2
2 changed files with 201 additions and 116 deletions

36
sea.js
View File

@ -44,6 +44,7 @@
var user = root._.user || (root._.user = root.chain()); // create a user context. var user = root._.user || (root._.user = root.chain()); // create a user context.
user.create = User.create; // attach a factory method to it. user.create = User.create; // attach a factory method to it.
user.auth = User.auth; // and a login method. user.auth = User.auth; // and a login method.
user.remember = User.remember; // and a credentials persisting method.
return user; // return the user! return user; // return the user!
} }
@ -74,13 +75,15 @@
// Well first we have to actually create a user. That is what this function does. // Well first we have to actually create a user. That is what this function does.
User.create = function(alias, pass, cb){ User.create = function(alias, pass, cb){
var root = this.back(-1); var root = this.back(-1);
cb = cb || function(){}; var doCreate = function(resolve, reject){
// Because more than 1 user might have the same username, we treat the alias as a list of those users. // Because more than 1 user might have the same username, we treat the alias as a list of those users.
root.get('alias/'+alias).get(function(at, ev){ root.get('alias/'+alias).get(function(at, ev){
ev.off(); ev.off();
if(at.put){ if(at.put){
// If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed. // If we can enforce that a user name is already taken, it might be nice to try, but this is not guaranteed.
return cb({err: Gun.log("User already created!")}); var err = 'User already created!';
Gun.log(err);
return reject({err: err});
} }
var user = {alias: alias, salt: Gun.text.random(64)}; var user = {alias: alias, salt: Gun.text.random(64)};
// pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it. // pseudo-randomly create a salt, then use CryptoJS's PBKDF2 function to extend the password with it.
@ -108,23 +111,27 @@
// next up, we want to associate the alias with the public key. So we add it to the alias list. // next up, we want to associate the alias with the public key. So we add it to the alias list.
var ref = root.get('alias/'+alias).put(Gun.obj.put({}, tmp, Gun.val.rel.ify(tmp))); var ref = root.get('alias/'+alias).put(Gun.obj.put({}, tmp, Gun.val.rel.ify(tmp)));
// callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack) // callback that the user has been created. (Note: ok = 0 because we didn't wait for disk to ack)
cb({ok: 0, pub: pair.pub}); resolve({ok: 0, pub: pair.pub});
}); });
}); });
}); });
}); });
}; };
if (cb){doCreate(cb, cb)} else {return new Promise(doCreate)}
};
// now that we have created a user, we want to authenticate them! // now that we have created a user, we want to authenticate them!
User.auth = function(props, cb){ User.auth = function(props, cb){
var alias = props.alias, pass = props.pass, newpass = props.newpass; var alias = props.alias, pass = props.pass, newpass = props.newpass;
var root = this.back(-1); var root = this.back(-1);
cb = cb || function(){}; var doAuth = function(resolve, reject){
// load all public keys associated with the username alias we want to log in with. // load all public keys associated with the username alias we want to log in with.
root.get('alias/'+alias).get(function(at, ev){ root.get('alias/'+alias).get(function(at, ev){
ev.off(); ev.off();
if(!at.put){ if(!at.put){
// if no user, don't do anything. // if no user, don't do anything.
return cb({err: Gun.log("No user!")}); var err = 'No user!';
Gun.log(err);
return reject({err: err});
} }
// then attempt to log into each one until we find ours! // 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) // (if two users have the same username AND the same password... that would be bad)
@ -133,7 +140,7 @@
root.get(key).get(function(at, ev){ root.get(key).get(function(at, ev){
key = key.slice(4); key = key.slice(4);
ev.off(); ev.off();
if(!at.put){ return cb({err: "Public key does not exist!"}) } if(!at.put){ return reject({err: 'Public key does not exist!'}) }
// attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.) // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.)
SEA.read(at.put.salt, key).then(function(salt){ SEA.read(at.put.salt, key).then(function(salt){
return SEA.proof(pass, salt); return SEA.proof(pass, salt);
@ -157,7 +164,7 @@
user._.pub = key; user._.pub = key;
//console.log("authorized", user._); //console.log("authorized", user._);
// callbacks success with the user data credentials. // callbacks success with the user data credentials.
cb(user._); resolve(user._);
// emit an auth event, useful for page redirects and stuff. // emit an auth event, useful for page redirects and stuff.
Gun.on('auth', user._); Gun.on('auth', user._);
} }
@ -191,13 +198,24 @@
return; return;
} }
// Or else we failed to log in... // Or else we failed to log in...
console.log("Failed to sign in!"); Gun.log('Failed to sign in!');
cb({err: "Attempt failed"}); reject({err: 'Attempt failed'});
}); });
}); });
}); });
}); });
}; };
if (cb){doAuth(cb, cb)} else {return new Promise(doAuth)}
};
// now that we have created a user, we want to authenticate them!
User.remember = function(props, cb){
var doRemember = function(resolve, reject){
Gun.log('User.remember is TODO: still');
reject({ err: 'Not implemented.' });
}
if (cb){doRemember(cb, cb)} else {return new Promise(doRemember)}
};
// After we have a GUN extension to make user registration/login easy, we then need to handle everything else. // After we have a GUN extension to make user registration/login easy, we then need to handle everything else.
// We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change) // We do this with a GUN adapter, we first listen to when a gun instance is created (and when its options change)

View File

@ -8035,22 +8035,89 @@ describe('Gun', function(){
Gun().user && describe('User', function(){ Gun().user && describe('User', function(){
console.log('TODO: User! THIS IS AN EARLY ALPHA!!!'); console.log('TODO: User! THIS IS AN EARLY ALPHA!!!');
var user = Gun().user; var alias = 'dude';
var pass = 'my secret password';
var user = Gun().user();
['callback', 'Promise'].forEach(function(type){ ['callback', 'Promise'].forEach(function(type){
describe(type, function(){ describe(type, function(){
it.skip('create', function(done){ describe('create', function(){
it('new', function(done){
var check = function(ack){
expect(ack).to.not.be(undefined);
expect(ack).to.not.be('');
expect(ack).to.have.keys(['ok','pub']);
done();
};
// Gun.user.create - creates new user
if(type === 'callback'){
user.create(alias+type, pass, check);
} else {
user.create(alias+type, pass).then(check).catch(done);
}
});
it('conflict', function(done){
var gunLog = Gun.log; // Temporarily removing logging
Gun.log = function(){};
var check = function(ack){
expect(ack).to.not.be(undefined);
expect(ack).to.not.be('');
expect(ack).to.have.key('err');
expect(ack.err).not.to.be(undefined);
expect(ack.err).not.to.be('');
done();
};
// Gun.user.create - fails to create existing user
if(type === 'callback'){
user.create(alias+type, pass, check);
} else {
user.create(alias+type, pass).then(function(ack){
done('Failed to decline creating existing user!');
}).catch(check);
}
Gun.log = gunLog;
});
});
describe('auth', function(){
it('login', function(done){
var check = function(ack){
expect(ack).to.not.be(undefined);
expect(ack).to.not.be('');
expect(ack).to.not.have.key('err');
done();
};
var props = {alias: alias+'-'+type, pass: pass};
user.create(props.alias, props.pass).catch(function(){})
.then(function(){
// Gun.user.create - creates new user
if(type === 'callback'){
user.auth(props, check);
} else {
user.auth(props).then(check).catch(done);
}
});
});
it.skip('failed login', function(done){
done(); done();
}); });
it.skip('auth', function(done){ it.skip('new password', function(done){
done(); done();
}); });
it.skip('remember', function(done){ it.skip('failed new password', function(done){
done(); done();
}); });
}); });
describe('remember', function(){
it.skip('TBD', function(done){
done();
});
});
});
}); });
}); });