authenticate.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. var SEA = require('./sea');
  2. var Gun = SEA.Gun;
  3. const queryGunAliases = require('./query')
  4. const parseProps = require('./parse')
  5. // This is internal User authentication func.
  6. const authenticate = async (alias, pass, gunRoot) => {
  7. // load all public keys associated with the username alias we want to log in with.
  8. const aliases = (await queryGunAliases(alias, gunRoot))
  9. .filter(({ pub, at: { put } = {} } = {}) => !!pub && !!put)
  10. // Got any?
  11. if (!aliases.length) {
  12. throw { err: 'Public key does not exist!' }
  13. }
  14. let err
  15. // then attempt to log into each one until we find ours!
  16. // (if two users have the same username AND the same password... that would be bad)
  17. const users = await Promise.all(aliases.map(async ({ at: at, pub: pub }, i) => {
  18. // attempt to PBKDF2 extend the password with the salt. (Verifying the signature gives us the plain text salt.)
  19. const auth = parseProps(at.put.auth)
  20. // NOTE: aliasquery uses `gun.get` which internally SEA.read verifies the data for us, so we do not need to re-verify it here.
  21. // SEA.verify(at.put.auth, pub).then(function(auth){
  22. try {
  23. const proof = await SEA.work(pass, auth.s)
  24. const props = { pub: pub, proof: proof, at: at }
  25. // the proof of work is evidence that we've spent some time/effort trying to log in, this slows brute force.
  26. /*
  27. MARK TO @mhelander : pub vs epub!???
  28. */
  29. const salt = auth.salt
  30. const sea = await SEA.decrypt(auth.ek, proof)
  31. if (!sea) {
  32. err = 'Failed to decrypt secret! ' + i +'/'+aliases.length;
  33. return
  34. }
  35. // now we have AES decrypted the private key, from when we encrypted it with the proof at registration.
  36. // if we were successful, then that meanswe're logged in!
  37. const priv = sea.priv
  38. const epriv = sea.epriv
  39. const epub = at.put.epub
  40. // TODO: 'salt' needed?
  41. err = null
  42. if(typeof window !== 'undefined'){
  43. var tmp = window.sessionStorage;
  44. if(tmp && gunRoot._.opt.remember){
  45. window.sessionStorage.alias = alias;
  46. window.sessionStorage.tmp = pass;
  47. }
  48. }
  49. return Object.assign(props, { priv: priv, salt: salt, epub: epub, epriv: epriv })
  50. } catch (e) {
  51. err = 'Failed to decrypt secret!'
  52. throw { err }
  53. }
  54. }))
  55. var user = Gun.list.map(users, function(acc){ if(acc){ return acc } })
  56. if (!user) {
  57. throw { err: err || 'Public key does not exist!' }
  58. }
  59. return user
  60. }
  61. module.exports = authenticate;