diff --git a/www/login/index.html b/www/login/index.html index 04fc47400..b4143365d 100644 --- a/www/login/index.html +++ b/www/login/index.html @@ -12,16 +12,43 @@ width: 100%; box-sizing: border-box; } + body { + width: 80vw; + min-width: 1000px; + margin: auto; + } + div.box, div.logout { + width: 50%; + border: 1px solid black; + padding: 15px; + display: none; + } + input[type="text"], input[type="password"] { + width: 80%; + } + + #confirm { display: none; } -
-
-
+
+
+
+
- - + +
+ +
+
+ + +
+
+
+ +
diff --git a/www/login/main.js b/www/login/main.js index d24829503..239ca9c6b 100644 --- a/www/login/main.js +++ b/www/login/main.js @@ -3,10 +3,11 @@ define([ '/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-crypto/crypto.js', '/common/cryptpad-common.js', + '/login/credential.js', '/bower_components/tweetnacl/nacl-fast.min.js', '/bower_components/scrypt-async/scrypt-async.min.js', '/bower_components/jquery/dist/jquery.min.js', -], function (Config, Listmap, Crypto, Cryptpad) { +], function (Config, Listmap, Crypto, Cryptpad, Cred) { var $ = window.jQuery; var Scrypt = window.scrypt; var Nacl = window.nacl; @@ -20,10 +21,6 @@ define([ Crypto: Crypto, }; - var print = function (S, t) { - $('body').append($('<' + (t || 'p') + '>').text(S)); - }; - var hashFromCreds = function (username, password, len, cb) { Scrypt(password, username, @@ -35,94 +32,122 @@ define([ undefined); // format, could be 'base64' }; - var authenticated = function (password, next) { - console.log("Authenticated!"); - var secret = {}; - - secret.channel = password.slice(0, 32); - secret.key = password.slice(32, 48); - secret.junk = password.slice(48, 64); // consider reordering things - secret.curve = password.slice(64, 96); - secret.ed = password.slice(96, 128); + var Events = APP.Events = {}; + var alreadyExists = Events.alreadyExists = function () { + Cryptpad.alert("user account already exists."); + }; + var mismatchedPasswords = Events.mismatchedPasswords = function () { + Cryptpad.alert("passwords don't match!"); + }; - print(JSON.stringify(secret, null, 2), 'pre'); + var useBytes = function (bytes, opt) { + opt = opt || {}; + if (opt.remember) { + console.log("user would like to stay logged in"); + } else { + console.log("user would like to be forgotten"); + } - var config = { - websocketURL: Config.websocketURL, - channel: secret.channel, - data: {}, - crypto: Crypto.createEncryptor(secret.key), - loglevel: 0, + var entropy = { + used: 0, }; - console.log("creating proxy!"); - var rt = module.rt = Listmap.create(config); + // crypto hygeine + var consume = function (n) { + // explode if you run out of bytes + if (entropy.used + n > bytes.length) { + throw new Error('exceeded available entropy'); + } + if (typeof(n) !== 'number') { throw new Error('expected a number'); } + if (n <= 0) { + throw new Error('expected to consume a positive number of bytes'); + } - next(rt.proxy, function () { - Cryptpad.log("Ready!"); - }); - }; + // grab an unused slice of the entropy + var A = bytes.slice(entropy.used, entropy.used + n); - var useBytes = function (bytes) { - var firstSeed = bytes.slice(0, 18); - var secondSeed = bytes.slice(18, 35); + // account for the bytes you used so you don't reuse bytes + entropy.used += n; - var remainder = bytes.slice(34); + //console.info("%s bytes of entropy remaining", bytes.length - entropy.used); + return A; + }; - var seed = {}; - seed.keys = Crypto.createEditCryptor(null, firstSeed); + // consume 18 bytes of entropy for your encryption key + var encryptionSeed = consume(18); + // 16 bytes for a deterministic channel key + var channelSeed = consume(16); + // 32 bytes for a curve key + var curveSeed = consume(32); + // 32 more for a signing key + var edSeed = consume(32); - seed.keys.editKeyStr = seed.keys.editKeyStr.replace(/\//g, '-'); + var seed = {}; + var keys = seed.keys = Crypto.createEditCryptor(null, encryptionSeed); - seed.channel = Cryptpad.uint8ArrayToHex(secondSeed); + // 24 bytes of base64 + keys.editKeyStr = keys.editKeyStr.replace(/\//g, '-'); - console.log(seed); + // 32 bytes of hex + seed.channel = Cryptpad.uint8ArrayToHex(channelSeed); var channelHex = seed.channel; - var channel64 = Cryptpad.hexToBase64(channelHex); - - console.log(seed.keys.editKeyStr); - seed.editHash = Cryptpad.getEditHashFromKeys(channelHex, seed.keys.editKeyStr); + if (channelHex.length !== 32) { + throw new Error('invalid channel id'); + } - var secret = Cryptpad.getSecrets(seed.editHash); - console.log(secret); + var channel64 = Cryptpad.hexToBase64(channelHex); - console.log(seed.editHash); + seed.editHash = Cryptpad.getEditHashFromKeys(channelHex, keys.editKeyStr); + //console.log("edithash: %s", seed.editHash); - //return; + var secret = Cryptpad.getSecrets(seed.editHash); var config = { websocketURL: Cryptpad.getWebsocketURL(), channel: channelHex, data: {}, - validateKey: seed.keys.validateKey || undefined, - readOnly: seed.keys && !seed.keys.editKeyStr, + validateKey: keys.validateKey, // derived validation key crypto: Crypto.createEncryptor(seed.keys), }; var rt = APP.rt = Listmap.create(config); rt.proxy.on('create', function (info) { - console.log('created'); - //console.log(info); + console.log("loading user profile"); }) .on('ready', function (info) { + console.log(info); console.log('ready'); - //console.log(info); - var proxy = rt.proxy; +/* if the user is registering, we expect that the userDoc will be empty +*/ + if (opt.register) { + if (Object.keys(proxy).length) { + alreadyExists(); + } + } + var now = +(new Date()); if (!proxy.atime) { console.log("first time visiting!"); proxy.atime = now; + + var name = proxy['cryptpad.username'] = opt.name; + console.log("setting name to %s", name); } else { console.log("last visit was %ss ago", (now - proxy.atime) / 1000); proxy.atime = now; } - console.log(proxy); + var userHash = '/1/edit/' + [channel64, keys.editKeyStr].join('/'); + + console.log("remembering your userhash"); + Cryptpad.login(userHash, opt.remember); + //console.log(userHash); + //console.log(proxy); }) .on('disconnect', function (info) { console.log('disconnected'); @@ -130,38 +155,81 @@ define([ }); }; - var isValidUsername = function (name) { - return !!name; - }; + var $warning = $('#warning'); + var $login = $('#login'); + var $username = $('#username'); + var $password = $('#password'); + var $confirm = $('#confirm'); + var $remember = $('#remember'); - var isValidPassword = function (passwd) { - return !!passwd; + var revealLogin = function () { + $('.box').slideDown(); }; - var $username = $('#username'); - var $password = $('#password'); + var $logoutBox = $('div.logout'); + var $logout = $('#logout').click(function () { + Cryptpad.logout(function () { + // noop? + $logout.slideUp(); + revealLogin(); + }); + }); - 0 && hashFromCreds('ansuz', 'pewpewpew', 128, useBytes); + var $register = $('#register').click(function () { + if (!$register.length) { return; } + var e = $register[0]; + if (e.checked) { + $confirm.slideDown(); + $login.text(Cryptpad.Messages._getKey('login_register')); + } + else { + $confirm.slideUp(); + $login.text(Cryptpad.Messages._getKey('login_login')); + } + }); + + var resetUI = function () { + $username.val(""); + $password.val(""); + $confirm.val(""); + $remember[0].checked = false; + $register[0].checked = false; + }; - $('#login').click(function () { + if (Cryptpad.getUserHash()) { + //Cryptpad.alert("You are already logged in!"); + $logoutBox.slideDown(); + } else { + revealLogin(); + } + + $login.click(function () { var uname = $username.val(); var passwd = $password.val(); + var confirm = $confirm.val(); + var remember = $remember[0].checked; + var register = $register[0].checked; - if (!isValidUsername(uname)) { + if (!Cred.isValidUsername(uname)) { return void Cryptpad.alert('invalid username'); } - - if (!isValidPassword(passwd)) { + if (!Cred.isValidPassword(passwd)) { return void Cryptpad.alert('invalid password'); } + if (register && !Cred.passwordsMatch(passwd, confirm)) { + return mismatchedPasswords(); + } - $username.val(""); - $password.val(""); + resetUI(); - // we need 18 bytes for the regular crypto + // consume 128 bytes, to be divided later + // we can safely increase this size, but we don't need much right now hashFromCreds(uname, passwd, 128, function (bytes) { - //console.log(bytes); - useBytes(bytes); + useBytes(bytes, { + remember: remember, + register: register, + name: uname, + }); }); }); });