206 lines
7.1 KiB
JavaScript
206 lines
7.1 KiB
JavaScript
'use strict';
|
|
|
|
// process.stdout.isTTY
|
|
var form = require('terminal-forms.js').create(process.stdin, process.stdout);
|
|
//var dns = form.PromiseA.promisifyAll(require('dns'));
|
|
var OAUTH3 = require('../oauth3.node.js');
|
|
// TODO change to ._hooks
|
|
OAUTH3._hooks = require('../oauth3.node.storage.js');
|
|
// directives = { get, set }
|
|
// sessions = { get, set }
|
|
/*
|
|
OAUTH3._hooks.directives.get = require('../oauth3.node.storage.js').directives.get;
|
|
OAUTH3._hooks.directives.set = require('../oauth3.node.storage.js').directives.set;
|
|
OAUTH3._hooks.session.get = require('../oauth3.node.storage.js').sessions.get;
|
|
OAUTH3._hooks.session.set = require('../oauth3.node.storage.js').sessions.set;
|
|
*/
|
|
|
|
// opts = { email, providerUri }
|
|
module.exports.login = function (options) {
|
|
options = options || {};
|
|
var url = require('url');
|
|
//console.log('stdin tty', process.stdin.isTTY);
|
|
//console.log('stdout tty', process.stdout.isTTY);
|
|
var oauth3;
|
|
var opts = {
|
|
email: options.email
|
|
, providerUri: options.providerUri
|
|
};
|
|
if (opts.form) {
|
|
form = opts.form;
|
|
}
|
|
var email;
|
|
var providerUrl;
|
|
var providerUri;
|
|
var sameProvider;
|
|
var username;
|
|
|
|
function getSession() {
|
|
var username;
|
|
|
|
// TODO lookup uuid locally before performing loginMeta
|
|
// TODO lookup token locally before performing loginMeta / otp
|
|
return OAUTH3.authn.loginMeta(oauth3._providerDirectives, { email: email }).then(function (/*result*/) {
|
|
return { node: email, type: 'email' };
|
|
}, function (/*err*/) {
|
|
// TODO require hashcash to create user account
|
|
function confirmCreateAccount() {
|
|
// TODO directives should specify private (invite-only) vs internal (request) vs public (allow) accounts
|
|
return form.ask({
|
|
label: "We don't recognize that address. Do you want to create a new account? [Y/n] "
|
|
, type: 'text' // TODO boolean with default Y or N
|
|
}).then(function (result) {
|
|
if (!result.input) {
|
|
result.input = 'Y';
|
|
}
|
|
|
|
// TODO needs backup address if email is on same domain as login
|
|
result.input = result.input.toLowerCase();
|
|
|
|
if ('y' !== result.input) {
|
|
return getCurrentUserEmail();
|
|
}
|
|
|
|
if (!sameProvider) {
|
|
return { node: email, type: 'email' };
|
|
}
|
|
|
|
return form.ask({
|
|
label: "What's your recovery email (or cloud mail) address? ", type: 'email'
|
|
}).then(function (recoveryResult) {
|
|
return {
|
|
node: email
|
|
, type: 'name'
|
|
, recovery: recoveryResult.result || recoveryResult.input
|
|
};
|
|
});
|
|
});
|
|
}
|
|
|
|
return confirmCreateAccount();
|
|
}).then(function (user) {
|
|
// TODO skip if token exists locally
|
|
var email = (user.recovery || user.node);
|
|
form.println("Sending login code to '" + email + "'...");
|
|
return OAUTH3.authn.otp(oauth3._providerDirectives, { email: email }).then(function (otpResult) {
|
|
return form.ask({
|
|
label: "What's your login code? "
|
|
, help: "(it was sent to '" + email + "' and looks like 1234-5678-9012)"
|
|
// onkeyup
|
|
// ondebounce
|
|
// onchange
|
|
// regexp // html5 name?
|
|
, onReturnAsync: function (rs, ws, input/*, ch*/) {
|
|
var formatted = input.toLowerCase().replace(/[^\d]+/g, '');
|
|
|
|
if (12 !== formatted.length) {
|
|
return form.PromiseA.reject(new Error("invalid code please try again in the format xxxx-yyyy-zzzz"));
|
|
}
|
|
|
|
formatted = formatted.match(/.{4,4}/g).join('-');
|
|
|
|
if (14 !== formatted.split('').length) {
|
|
return form.PromiseA.reject(new Error("invalid code '" + formatted + "', please try again xxxx-yyyy-zzzz"));
|
|
}
|
|
|
|
var data = {
|
|
username: email
|
|
, username_type: 'email'
|
|
, client_id: OAUTH3.uri.normalize(oauth3._providerDirectives.issuer)
|
|
, client_uri: OAUTH3.uri.normalize(oauth3._providerDirectives.issuer)
|
|
, otp_code: formatted
|
|
, otp_uuid: otpResult.data.uuid
|
|
};
|
|
|
|
// returns session instead of input
|
|
var colors = require('colors');
|
|
form.setStatus(colors.dim("authenticating with server..."));
|
|
return OAUTH3.authn.resourceOwnerPassword(oauth3._providerDirectives, data).then(function (result) {
|
|
return result;
|
|
}, function (/*err*/) {
|
|
// TODO test error
|
|
return form.PromiseA.reject(new Error("The code '" + formatted + "' is mistyped or incorrect. Double check and try again."));
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function getCurrentUserEmail() {
|
|
return form.ask({
|
|
label: "What's your email (or cloud mail) address? ", type: 'email', value: opts.email
|
|
}).then(function (emailResult) {
|
|
opts.email = undefined;
|
|
email = (emailResult.result || emailResult.input);
|
|
var emailParts = email.split('@');
|
|
var domain = emailParts[1];
|
|
username = emailParts[0];
|
|
providerUrl = 'https://' + domain;
|
|
providerUri = domain;
|
|
|
|
var urlObj = url.parse(providerUrl);
|
|
// TODO get unique client id for bootstrapping app
|
|
oauth3 = OAUTH3.create(urlObj);
|
|
return oauth3.setProvider(domain).then(function () {
|
|
sameProvider = true;
|
|
// ignore
|
|
}, function () {
|
|
function askOauth3Url() {
|
|
return form.ask({
|
|
label: "What's your OAuth3 Provider URL? ", type: 'url', value: opts.providerUri
|
|
}).then(function (urlResult) {
|
|
opts.providerUri = undefined;
|
|
providerUrl = urlResult.result || urlResult.input;
|
|
providerUri = OAUTH3.uri.normalize(providerUrl);
|
|
|
|
var urlObj = url.parse(providerUrl);
|
|
// TODO get unique client id for bootstrapping app
|
|
oauth3 = OAUTH3.create(urlObj);
|
|
return oauth3.setProvider(providerUri).then(function () {
|
|
// ignore
|
|
}, function (err) {
|
|
form.println(err.stack || err.message || err.toString());
|
|
return askOauth3Url();
|
|
});
|
|
});
|
|
}
|
|
|
|
return askOauth3Url();
|
|
});
|
|
});
|
|
}
|
|
|
|
return getCurrentUserEmail().then(function () {
|
|
return OAUTH3._hooks.meta.get(email).then(function (id) {
|
|
if (!id) {
|
|
return null;
|
|
}
|
|
return OAUTH3._hooks.sessions.get(providerUri, id).then(function (session) {
|
|
if (session) {
|
|
return session;
|
|
}
|
|
return null;
|
|
});
|
|
});
|
|
}).then(function (session) {
|
|
if (session) {
|
|
return session;
|
|
}
|
|
|
|
return getSession().then(function (sessionResult) {
|
|
var session = sessionResult.result;
|
|
var id = require('crypto').createHash('sha256').update(session.token.sub || '').digest('hex');
|
|
|
|
return OAUTH3._hooks.sessions.set(providerUri, session, id).then(function (session) {
|
|
return OAUTH3._hooks.meta.set(email, id).then(function () {
|
|
return session;
|
|
});
|
|
});
|
|
});
|
|
}).then(function (session) {
|
|
oauth3.__session = session;
|
|
return oauth3;
|
|
});
|
|
};
|