403 lines
12 KiB
JavaScript
403 lines
12 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
angular.module('yololiumApp')
|
||
|
.controller('LoginController3', [
|
||
|
'$scope'
|
||
|
, '$q'
|
||
|
, '$timeout'
|
||
|
, '$modalInstance'
|
||
|
, 'Oauth3'
|
||
|
, 'DaplieApiSession'
|
||
|
, 'DaplieApiRequest'
|
||
|
, 'LdsAccount'
|
||
|
, 'myLoginOptions'
|
||
|
, function (
|
||
|
$scope
|
||
|
, $q
|
||
|
, $timeout
|
||
|
, $modalInstance
|
||
|
, Oauth3
|
||
|
, Oauth3ApiSession
|
||
|
, Oauth3ApiRequest
|
||
|
, LdsAccount
|
||
|
, opts
|
||
|
) {
|
||
|
opts = opts || {};
|
||
|
var scope = this;
|
||
|
var secretMinLen = scope.secretMinLength = Oauth3ApiSession.secretMinLength;
|
||
|
//var usernameMinLen = Oauth3ApiSession.usernameMinLength;
|
||
|
var mySession;
|
||
|
|
||
|
scope.hideSocial = opts.hideSocial;
|
||
|
scope.flashMessage = opts.flashMessage;
|
||
|
scope.flashMessageClass = opts.flashMessageClass;
|
||
|
|
||
|
scope.delta = { localLogin: {} };
|
||
|
|
||
|
function onDaplieLogin(oauth3Session) {
|
||
|
console.log('DEBUG onLogin');
|
||
|
console.log(oauth3Session);
|
||
|
// TODO if there is not a default account, show user-switching screen
|
||
|
// this will close both on user/pass and social login
|
||
|
scope.flashMessage = "You've logged in. Please wait while we download some ward and stake data...";
|
||
|
scope.flashMessageClass = 'alert-info';
|
||
|
return Oauth3ApiRequest.profile(oauth3Session).then(function (profile) {
|
||
|
console.log('DEBUG profile');
|
||
|
console.log(profile);
|
||
|
|
||
|
$modalInstance.close(oauth3Session);
|
||
|
/*
|
||
|
return LdsAccount.verifyAccount(ldsSession, profile).then(function () {
|
||
|
scope.flashMessage = "Done!";
|
||
|
scope.flashMessageClass = 'alert-success';
|
||
|
console.log('DEBUG verifiedAccount');
|
||
|
$modalInstance.close(ldsSession);
|
||
|
});
|
||
|
*/
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function handleLoginException(err) {
|
||
|
scope.formState = 'login';
|
||
|
|
||
|
console.error("[Uknown Error] Either 'resource owner password' or 'delegated' login");
|
||
|
console.warn(err.stack);
|
||
|
scope.flashMessage = err.message || err.code;
|
||
|
scope.flashMessageClass = "alert-danger";
|
||
|
}
|
||
|
|
||
|
function handleSuccess(session) {
|
||
|
return Oauth3ApiSession.requireAccount(session).then(onDaplieLogin, function (err) {
|
||
|
if ('E_NO_LDSACCOUNT' !== err.code) {
|
||
|
throw err;
|
||
|
}
|
||
|
|
||
|
scope.hideSocial = true;
|
||
|
scope.flashMessage = err.message;
|
||
|
scope.flashMessageClass = "alert-warning";
|
||
|
}).catch(handleLoginException);
|
||
|
}
|
||
|
|
||
|
function handleLoginError(err) {
|
||
|
console.error('handleLoginError');
|
||
|
console.error(err);
|
||
|
console.warn(err.stack);
|
||
|
if (!err.message) {
|
||
|
throw err;
|
||
|
}
|
||
|
|
||
|
scope.formState = 'login';
|
||
|
|
||
|
scope.flashMessage = err.message || err.code;
|
||
|
scope.flashMessageClass = "alert-warning";
|
||
|
|
||
|
throw err;
|
||
|
}
|
||
|
|
||
|
scope.loginStrategies = [
|
||
|
{ label: 'Facebook'
|
||
|
, name: 'facebook'
|
||
|
, faImage: ""
|
||
|
, faClass: "fa-facebook"
|
||
|
, btnClass: "btn-facebook"
|
||
|
, login: function () {
|
||
|
var providerUri = (window.location.host + window.location.pathname).replace(/\/$/g, '');
|
||
|
var providerApiUri = 'https://oauth3.org';
|
||
|
|
||
|
return Oauth3ApiSession.login({
|
||
|
providerUri: providerUri // 'daplie.com/connect'
|
||
|
, scope: [ 'email' ]
|
||
|
, redirectUri: 'https://' + providerUri + '/oauth3.html'
|
||
|
, popup: true
|
||
|
// TODO XXX use whatever variable it is for apiHost
|
||
|
, authorizationRedirect: providerApiUri + '/api/org.oauth3.consumer/authorization_redirect/facebook.com'
|
||
|
}).then(handleSuccess, handleLoginError).catch(handleLoginException);
|
||
|
}
|
||
|
}
|
||
|
, { label: 'Google+'
|
||
|
, name: 'google'
|
||
|
, faImage: ""
|
||
|
, faClass: "fa-google-plus"
|
||
|
, btnClass: "btn-google-plus"
|
||
|
, login: function () {
|
||
|
return Oauth3ApiSession.logins.authorizationRedirect({
|
||
|
providerUri: 'google.com'
|
||
|
, scope: [ 'https://www.googleapis.com/auth/plus.login' ]
|
||
|
, redirectUri: 'https://beta.ldsconnect.org/oauth3.html'
|
||
|
, popup: true
|
||
|
}).then(handleSuccess, handleLoginError).catch(handleLoginException);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
, { label: 'LDS.org Account'
|
||
|
, faImage: "images/moroni-128px.png"
|
||
|
, faClass: ""
|
||
|
, btnClass: "openid"
|
||
|
, login: scope.loginWithLdsconnect
|
||
|
}
|
||
|
*/
|
||
|
];
|
||
|
|
||
|
scope.hideSocial = opts.hideSocial;
|
||
|
scope.flashMessage = opts.flashMessage;
|
||
|
scope.flashMessageClass = opts.flashMessageClass;
|
||
|
|
||
|
// This dialog is opened to update necessary account details
|
||
|
// It should be passed options to inform the dialog which
|
||
|
// missing fields are necessary to show at this time
|
||
|
//
|
||
|
// Examples:
|
||
|
// we want to get facebook but haven't connected yet, so we should show the connection dialog
|
||
|
// we just logged in for the first time and don't have an account or a local login
|
||
|
function onLogout() {
|
||
|
scope.session = null;
|
||
|
scope.account = null;
|
||
|
scope.accounts = null;
|
||
|
}
|
||
|
|
||
|
function onLogin(session) {
|
||
|
// session is always ensured as part of login
|
||
|
mySession = session;
|
||
|
|
||
|
var defaultAction = '';
|
||
|
var emails = [];
|
||
|
|
||
|
scope.account = scope.account || mySession.account || {};
|
||
|
if (scope.account.id) {
|
||
|
defaultAction = 'update';
|
||
|
}
|
||
|
|
||
|
scope.formAction = scope.formAction || defaultAction;
|
||
|
|
||
|
scope.account = scope.account || {};
|
||
|
scope.delta = scope.delta || {};
|
||
|
scope.deltaEmail = { type: 'email' };
|
||
|
scope.deltaPhone = { type: 'phone' };
|
||
|
scope.delta.localLogin = scope.delta.localLogin || {};
|
||
|
scope.logins = mySession.logins.map(function (login) {
|
||
|
return {
|
||
|
comment: ('local' === (login.provider || login.type)) ? (login.uid || 'username') : login.provider
|
||
|
, id: login.id
|
||
|
, uid: login.uid
|
||
|
, provider: login.provider
|
||
|
, type: login.type
|
||
|
, link: true
|
||
|
};
|
||
|
});
|
||
|
|
||
|
mySession.logins.some(function (login) {
|
||
|
if ('local' === (login.type || login.provider)) {
|
||
|
scope.account.localLoginId = login.id;
|
||
|
scope.delta.localLogin.id = login.id;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// login is always ensured prior to account
|
||
|
mySession.logins.forEach(function (l) {
|
||
|
(l.emails||[]).forEach(function (email) {
|
||
|
if (email && email.value) {
|
||
|
emails.push(email);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// TODO combo box for creating new logins
|
||
|
scope.emails = emails;
|
||
|
scope.deltaEmail.node = (emails[0] || {}).value;
|
||
|
|
||
|
if (!scope.deltaEmail.node) {
|
||
|
mySession.logins.some(function (login) {
|
||
|
scope.deltaEmail.node = (login.emails && login.emails[0] || {}).value;
|
||
|
return scope.deltaEmail.node;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if (mySession.logins.length) {
|
||
|
scope.formAction = 'create';
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// TODO check mySession
|
||
|
if (mySession.logins.length >= 2) {
|
||
|
scope.recoverable = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
scope.checkTotp = function (nodeObj) {
|
||
|
var tokenLen = 6;
|
||
|
var len = (nodeObj.totp||'').replace(/\D/g, '').length;
|
||
|
|
||
|
if (len === tokenLen) {
|
||
|
nodeObj.totpMessage = 'So far, so good.';
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nodeObj.totpMessage = 'Token is too short '
|
||
|
+ len + '/' + tokenLen
|
||
|
+ ' (needs to be ' + tokenLen + '+ digits)'
|
||
|
;
|
||
|
};
|
||
|
scope.checkSecret = function (nodeObj) {
|
||
|
var len = (nodeObj.secret||'').length;
|
||
|
var meetsLen = (len >= secretMinLen);
|
||
|
|
||
|
if (meetsLen) {
|
||
|
nodeObj.secretMessage = 'Login when ready, captain!';
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nodeObj.secretMessage = 'Passphrase is too short '
|
||
|
+ len + '/' + secretMinLen
|
||
|
+ ' (needs to be ' + secretMinLen + '+ characters)'
|
||
|
;
|
||
|
};
|
||
|
|
||
|
scope.submitLogin = function (nodeObj) {
|
||
|
var promise;
|
||
|
scope.flashMessage = "";
|
||
|
scope.flashMessageClass = "alert-danger";
|
||
|
|
||
|
if (scope._loginPromise) {
|
||
|
promise = scope._loginPromise;
|
||
|
} else {
|
||
|
promise = $q.when();
|
||
|
}
|
||
|
|
||
|
// TODO this must be implemented in all platforms
|
||
|
nodeObj.secret = nodeObj.secret.trim();
|
||
|
|
||
|
console.log('submitLogin nodeObj', nodeObj);
|
||
|
if ('create' === scope.formState) {
|
||
|
nodeObj.kdf = 'PBKDF2';
|
||
|
nodeObj.bits = 128;
|
||
|
nodeObj.algo = 'SHA-256';
|
||
|
nodeObj.iter = Math.floor(Math.random() * 100) + 1001;
|
||
|
}
|
||
|
|
||
|
promise = window.getProofOfSecret(nodeObj);
|
||
|
|
||
|
if ('create' === scope.formState) {
|
||
|
// TODO redo soft check
|
||
|
// TODO move to OAuth3
|
||
|
return promise.then(function (kdf) {
|
||
|
kdf.secret = null;
|
||
|
//console.log('Oauth3.logins', Object.keys(Oauth3.logins));
|
||
|
return Oauth3ApiSession.createLogin(kdf.node, kdf.type || 'email', null, {
|
||
|
kdf: kdf.kdf
|
||
|
, algo: kdf.algo
|
||
|
//, hash: kdf.algo
|
||
|
, iter: kdf.iter
|
||
|
, bits: kdf.bits
|
||
|
, salt: kdf.salt
|
||
|
, proof: kdf.proof
|
||
|
//, shadow: kdf.proof
|
||
|
}, null);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return promise.then(function (kdf) {
|
||
|
// TODO change the state to authenticating for social logins as well
|
||
|
scope.formState = 'authenticating';
|
||
|
// ALL THE SCOPES!!!
|
||
|
// TODO
|
||
|
//return Oauth3.requests.resourceOwnerPassword('https://daplie.com/connect', nodeObj.node, kdf.proof, { scope: '*', appId: 'ID__b5db805e27cc27a0ee8eddf42f46' }).then(function (session) {
|
||
|
return Oauth3ApiSession.login({
|
||
|
username: nodeObj.node
|
||
|
//, usernameType: nodeObj.nodeType
|
||
|
, password: kdf.proof
|
||
|
, totp: nodeObj.totp
|
||
|
//, mfa: kdf.mfa
|
||
|
, scope: '*'
|
||
|
}).then(function (session) {
|
||
|
console.log('[session]', session);
|
||
|
if (session.error) {
|
||
|
throw new Error("no oauth3 session");
|
||
|
}
|
||
|
return Oauth3ApiSession.requireAccount(session).then(onDaplieLogin);
|
||
|
}, handleLoginError).catch(handleLoginException);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
scope.checkLdsLogin = function (nodeObj) {
|
||
|
var username;
|
||
|
var myPromise;
|
||
|
var nameError;
|
||
|
|
||
|
scope.formState = 'login';
|
||
|
nodeObj.claimable = false;
|
||
|
nodeObj.message = '';
|
||
|
scope.flashMessage = '';
|
||
|
scope.flashMessageClass = "alert-warning";
|
||
|
username = nodeObj.node;
|
||
|
|
||
|
$timeout.cancel(scope._loginTimeout);
|
||
|
|
||
|
if (!username || 'null' === username || 'undefined' === username) {
|
||
|
myPromise = false;
|
||
|
scope.formState = 'invalid';
|
||
|
nodeObj.message = '';
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// returns true or error object
|
||
|
nameError = Oauth3ApiSession.validateUsername(nodeObj.node);
|
||
|
if (nameError.message) {
|
||
|
myPromise = false;
|
||
|
scope.formState = 'invalid';
|
||
|
nodeObj.message = nameError.message;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nodeObj.message = 'Checking username...';
|
||
|
myPromise = scope._loginTimeout = $timeout(function () {
|
||
|
scope._loginPromise = Oauth3ApiSession.getMeta(nodeObj.node, nodeObj.type || 'email').then(function (kdf) {
|
||
|
// kdf
|
||
|
nodeObj.kdf = kdf.kdf;
|
||
|
nodeObj.algo = kdf.algo;
|
||
|
nodeObj.bits = kdf.bits;
|
||
|
nodeObj.iter = kdf.iter;
|
||
|
nodeObj.salt = kdf.salt;
|
||
|
scope.showTotp = kdf.totpEnabledAt || kdf.totpEnabled || kdf.totp;
|
||
|
|
||
|
myPromise = false;
|
||
|
nodeObj.message = "'" + username + "' is already registered."
|
||
|
+ ' Welcome back!'
|
||
|
;
|
||
|
scope.formState = 'login';
|
||
|
}, function () {
|
||
|
// TODO test that error is simply not exists
|
||
|
// and not a server error
|
||
|
if (myPromise !== scope._loginTimeout) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
scope.formState = 'create';
|
||
|
nodeObj.message = "'" + username + "' is available!";
|
||
|
}).catch(function (err) {
|
||
|
nodeObj.message = '';
|
||
|
|
||
|
scope.formState = 'login';
|
||
|
scope.flashMessage = "[Uknown Error] " + err.message
|
||
|
+ " (might need to wait a minute and try again)";
|
||
|
scope.flashMessageClass = "alert-danger";
|
||
|
throw err;
|
||
|
});
|
||
|
}, 250);
|
||
|
|
||
|
return scope._loginTimeout;
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Begin
|
||
|
//
|
||
|
//Oauth3ApiSession.onLogin($scope, onDaplieLogin);
|
||
|
Oauth3ApiSession.onLogout($scope, onLogout);
|
||
|
//Oauth3ApiSession.checkSession().then(onDaplieLogin, onLogout);
|
||
|
if (false) {
|
||
|
// prevent lint warnings until I figure out how I'll use this
|
||
|
onLogin();
|
||
|
}
|
||
|
}]);
|