basic node.js authentication tested

This commit is contained in:
AJ ONeal 2017-03-21 01:02:41 -06:00
parent afb021af9b
commit cc4af8f95a
5 changed files with 109 additions and 21 deletions

View File

@ -3,14 +3,17 @@
// process.stdout.isTTY
var form = require('terminal-forms.js').create(process.stdin, process.stdout);
var OAUTH3 = require('../oauth3.node.js');
// TODO change to ._hooks
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').session._get;
OAUTH3.hooks.session._set = require('../oauth3.node.storage.js').session._set;
var url = require('url');
console.log('stdin tty', process.stdin.isTTY);
console.log('stdout tty', process.stdout.isTTY);
//console.log('stdin tty', process.stdin.isTTY);
//console.log('stdout tty', process.stdout.isTTY);
form.ask({ label: "What's your OAuth3 Provider URL? ", type: 'url' }).then(function (urlResult) {
var urlObj = url.parse(urlResult.input);
var urlObj = url.parse(urlResult.result || urlResult.input);
// TODO get unique client id for bootstrapping app
var oauth3 = OAUTH3.create(urlObj);
var providerPromise = oauth3.setProvider(urlObj.host + urlObj.pathname);
@ -20,23 +23,79 @@ form.ask({ label: "What's your OAuth3 Provider URL? ", type: 'url' }).then(funct
// TODO lookup uuid locally before performing loginMeta
// TODO lookup token locally before performing loginMeta / otp
return providerPromise.then(function () {
return OAUTH3.authn.loginMeta(oauth3._providerDirectives, { email: emailResult.input }).then(function (result) {
return OAUTH3.authn.loginMeta(oauth3._providerDirectives, { email: emailResult.input }).then(function (/*result*/) {
return emailResult.input;
}, function (/*err*/) {
// TODO require hashcash to create user account
console.log(result);
return form.PromiseA.reject(new Error("not implemented"));
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';
}
result.input = result.input.toLowerCase();
if ('y' !== result.input) {
return getCurrentUserEmail();
}
return emailResult.input;
});
}
return confirmCreateAccount();
});
});
});
}
getCurrentUserEmail().then(function (email) {
return getCurrentUserEmail().then(function (email) {
// TODO skip if token exists locally
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 '" + urlResult.input + "' and looks like 1234-5678-9012)"
}).then(function () {
console.log(otpResult);
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 (results) {
var session = results.result;
form.println('session:');
form.println(session);
});
});
});

View File

@ -817,7 +817,8 @@
}
resolve({
request: xhr
_request: xhr
, headers: null // TODO
, data: data
, status: xhr.status
});
@ -1023,10 +1024,8 @@
this._clientUri = OAUTH3.clientUri(location);
}
if (this._providerUri) {
p = OAUTH3.discover(this._providerUri, { client_id: this._clientUri }).then(function (/*directives*/) {
console.error("BUG: there's some jquery in oauth3.core.js that needs to be removed and tested");
$('.js-signin').removeAttr('disabled');
});
// returns directives
p = OAUTH3.discover(this._providerUri, { client_id: this._clientUri });
}
return OAUTH3.discover(this._clientUri, { client_id: this._clientUri }).then(function (clientDirectives) {

View File

@ -130,6 +130,7 @@ OAUTH3.urls.resourceOwnerPassword = function (directive, opts) {
var clientUri = opts.client_uri;
var args = directive[type];
var otpCode = opts.otp || opts.otpCode || opts.otp_code || opts.otpToken || opts.otp_token || undefined;
// TODO require user agent
var params = {
client_id: opts.client_id || opts.client_uri
, client_uri: opts.client_uri
@ -239,20 +240,23 @@ OAUTH3.authn.loginMeta = function (directive, opts) {
return OAUTH3.request({
method: directive.credential_meta.method || 'GET'
// TODO lint urls
// TODO client_uri
, url: OAUTH3.url.resolve(directive.issuer, directive.credential_meta.url)
.replace(':type', 'email')
.replace(':id', opts.email)
});
};
OAUTH3.authn.otp = function (directive, opts) {
// TODO client_uri
var preq = {
method: directive.credential_otp.method || 'POST'
, url: OAUTH3.url.resolve(directive.issuer, directive.credential_otp.url)
, data: {
// TODO replace with signed hosted file
client_agree_tos: 'oauth3.org/tos/draft'
, client_id: directive.issuer // In this case, the issuer is its own client
, client_uri: directive.issuer
// TODO unbreak the client_uri option (if broken)
, client_id: /*opts.client_id ||*/ OAUTH3.uri.normalize(directive.issuer) // In this case, the issuer is its own client
, client_uri: /*opts.client_uri ||*/ OAUTH3.uri.normalize(directive.issuer)
, request_otp: true
, username: opts.email
}
@ -268,6 +272,7 @@ OAUTH3.authn.resourceOwnerPassword = function (directive, opts) {
return OAUTH3.discover(providerUri, opts).then(function (directive) {
var prequest = OAUTH3.urls.resourceOwnerPassword(directive, opts);
// TODO return not the raw request?
return OAUTH3.request(prequest).then(function (req) {
var data = req.data;
data.provider_uri = providerUri;

View File

@ -22,6 +22,13 @@ OAUTH3._requestHelper = function (preq, opts) {
*/
return OAUTH3._node.request(preq, opts);
};
OAUTH3._base64.atob = function (base64) {
return new Buffer(base64, 'base64').toString('utf8');
};
OAUTH3._base64.btoa = function (text) {
return new Buffer(text, 'utf8').toString('base64');
};
OAUTH3._node = {};
OAUTH3._node.discover = function(providerUri/*, opts*/) {
return OAUTH3.request({
@ -76,10 +83,13 @@ OAUTH3._node._parseJson = function (resp) {
return PromiseA.reject(err);
}
resp.data = json;
return resp;
return {
headers: resp.headers
, status: resp.statusCode
, data: json
};
};
OAUTH3._logoutHelper = function(directives, opts) {
OAUTH3._logoutHelper = function(/*directives, opts*/) {
// TODO allow prompting of which account
return OAUTH3.PromiseA.reject(new Error("logout not yet implemented for node.js"));
};

View File

@ -18,4 +18,19 @@ module.exports = {
return directives;
}
}
, session: {
_get: function (providerUri) {
// TODO make safe
try {
return require(path.join(process.cwd(), providerUri + '.session.json'));
} catch(e) {
return null;
}
}
, _set: function (providerUri, session) {
fs.writeFileSync(path.join(process.cwd(), providerUri + '.session.json'), JSON.stringify(session, null, 2));
return session;
}
}
};