-
Benoit Lavenier authoredBenoit Lavenier authored
login-controllers.js 13.35 KiB
angular.module('cesium.login.controllers', ['cesium.services'])
.controller('LoginModalCtrl', LoginModalController)
.controller('AuthModalCtrl', AuthModalController)
.controller('AuthIdleCtrl', AuthIdleController)
;
function LoginModalController($scope, $timeout, $q, CryptoUtils, UIUtils, Modals, csSettings, Device, parameters) {
'ngInject';
$scope.computing = false;
$scope.pubkey = null;
$scope.formData = {};
$scope.showPubkey = false;
$scope.showComputePubkeyButton = false;
$scope.autoComputePubkey = false;
$scope.error = parameters && parameters.error;
$scope.isAuth = parameters && parameters.auth;
$scope.expectedPubkey = parameters && parameters.expectedPubkey;
var loginMethods = [
{id: 'PUBKEY', label: 'LOGIN.METHOD.PUBKEY'}
];
var authMethods = [
{id: 'SCRYPT_DEFAULT', label: 'LOGIN.METHOD.SCRYPT_DEFAULT'},
{
id: 'SCRYPT_ADVANCED', label: 'LOGIN.METHOD.SCRYPT_ADVANCED',
values: _.keys(CryptoUtils.constants.SCRYPT_PARAMS).reduce(function(res, key) {
return res.concat({id: key, label: 'LOGIN.SCRYPT.' + key, params: CryptoUtils.constants.SCRYPT_PARAMS[key]});
}, [{id: 'user', label: 'LOGIN.SCRYPT.USER', params: {}}])
},
{id: 'FILE', label: 'LOGIN.METHOD.FILE'}
];
$scope.showMethods = false;
// modal enter
$scope.enter = function() {
UIUtils.loading.hide();
// Should auto-compute pubkey ?
$scope.autoComputePubkey = ionic.Platform.grade.toLowerCase()==='a' &&
!UIUtils.screen.isSmall();
// Init remember me
$scope.formData.rememberMe = csSettings.data.rememberMe;
// Prepare methods
if (parameters && parameters.auth) {
$scope.methods = authMethods;
}
else {
// All methods : login and auth
$scope.methods = authMethods.concat(loginMethods);
}
// Init method
var defaultMethod = csSettings.data.login && csSettings.data.login.method || 'SCRYPT_DEFAULT';
$scope.formData.method = _.findWhere($scope.methods, {id: defaultMethod}) || $scope.methods[0];
$scope.changeMethod($scope.formData.method);
};
$scope.$on('modal.shown', $scope.enter);
// modal leave
$scope.leave = function() {
$scope.formData = {};
$scope.computing = false;
$scope.pubkey = null;
$scope.methods = [];
};
$scope.$on('modal.hide', $scope.leave);
// Login form submit
$scope.doLogin = function() {
if(!$scope.form.$valid) {
return;
}
// removeIf(no-device)
Device.keyboard.close();
// endRemoveIf(no-device)
var method = $scope.formData.method.id;
var promise;
// Scrypt
if (method === 'SCRYPT_DEFAULT' || method === 'SCRYPT_ADVANCED') {
if (!$scope.formData.username || !$scope.formData.password) return;
var scryptPrams = $scope.formData.scrypt && $scope.formData.scrypt.params;
UIUtils.loading.show();
promise = CryptoUtils.scryptKeypair($scope.formData.username, $scope.formData.password, scryptPrams)
.then(function(keypair) {
if (!keypair) return UIUtils.loading.hide(10);
var pubkey = CryptoUtils.util.encode_base58(keypair.signPk);
// Check pubkey
if ($scope.expectedPubkey && $scope.expectedPubkey != pubkey) {
$scope.pubkey = pubkey;
$scope.showPubkey = true;
$scope.pubkeyError = true;
return UIUtils.loading.hide(10);
}
$scope.error = null;
$scope.pubkeyError = false;
return {
pubkey: pubkey,
keypair: keypair,
params: ($scope.formData.scrypt && $scope.formData.scrypt.id != 'SCRYPT_DEFAULT') ? scryptPrams : undefined
};
})
.catch(UIUtils.onError('ERROR.CRYPTO_UNKNOWN_ERROR'));
}
// File
else if (method === 'FILE') {
if (!$scope.formData.file || !$scope.formData.file.valid || !$scope.formData.file.pubkey) return;
UIUtils.loading.show();
promise = CryptoUtils.readKeyFile($scope.formData.file, $scope.formData.keepAuth/*withSecret*/)
.then(function(keypair) {
if (!keypair) return UIUtils.loading.hide(10);
var pubkey = CryptoUtils.util.encode_base58(keypair.signPk);
// Check pubkey
if ($scope.expectedPubkey && $scope.expectedPubkey != pubkey) {
$scope.formData.file.valid = false;
return UIUtils.loading.hide(10);
}
$scope.error = null;
$scope.pubkeyError = false;
return {
pubkey: pubkey,
keypair: keypair,
params: $scope.formData.file
};
})
.catch(UIUtils.onError('ERROR.AUTH_FILE_ERROR'));
}
// Pubkey
else if (method === 'PUBKEY') {
if (!$scope.formData.pubkey) return;
promise = $q.when({
pubkey: $scope.formData.pubkey
});
}
if (!promise) {
console.warn('[login] unknown method: ', method);
return;
}
return promise.then(function(res) {
if (!res) return;
return $scope.closeModal({
pubkey: res.pubkey,
keypair: res.keypair,
method: method,
rememberMe: $scope.formData.rememberMe,
params: res.params
});
});
};
$scope.scryptFormDataChanged = function() {
if ($scope.computing) return; // avoid multiple call
$scope.pubkey = null;
$scope.pubkeyError = false;
$scope.showPubkey = !!$scope.formData.username && !!$scope.formData.password;
if ($scope.autoComputePubkey && $scope.showPubkey) {
$scope.computePubkey();
$scope.showComputePubkeyButton = false;
}
else {
$scope.showComputePubkeyButton = !$scope.autoComputePubkey && $scope.showPubkey;
}
};
$scope.$watch('formData.username + formData.password', $scope.scryptFormDataChanged, true);
$scope.computePubkey = function() {
$scope.showComputePubkeyButton = false;
$scope.computing = true;
$scope.pubkey = null;
return $timeout(function() {
var salt = $scope.formData.username;
var pwd = $scope.formData.password;
var scryptPrams = $scope.formData.scrypt && $scope.formData.scrypt.params;
return CryptoUtils.scryptSignPk(salt, pwd, scryptPrams)
.then(function (signPk) {
// If model has changed before the response, then retry
if (salt !== $scope.formData.username || pwd !== $scope.formData.password) {
return $scope.computePubkey();
}
$scope.pubkey = CryptoUtils.util.encode_base58(signPk);
if ($scope.expectedPubkey && $scope.expectedPubkey != $scope.pubkey) {
$scope.pubkeyError = true;
}
$scope.computing = false;
}
)
.catch(function (err) {
UIUtils.onError('ERROR.CRYPTO_UNKNOWN_ERROR')(err);
$scope.computing = false;
$scope.scryptFormDataChanged();
});
}, 100);
};
$scope.showJoinModal = function() {
$scope.closeModal();
$timeout(function() {
Modals.showJoin();
}, 300);
};
$scope.showAccountSecurityModal = function() {
$scope.closeModal();
$timeout(function() {
Modals.showAccountSecurity();
}, 300);
};
$scope.showHelpModal = function(parameters) {
return Modals.showHelp(parameters);
};
$scope.changeMethod = function(method){
console.debug("[login] method changed: ", method);
// Scrypt (advanced or not)
if (method && (method.id == "SCRYPT_DEFAULT" || method.id == "SCRYPT_ADVANCED")) {
$scope.changeScrypt(method.values && method.values[1]/*=default scrypt params*/);
$scope.autoComputePubkey = $scope.autoComputePubkey && (method.id == "SCRYPT_DEFAULT");
}
else {
$scope.formData.username = null;
$scope.formData.password = null;
$scope.formData.pubkey = null;
$scope.formData.computing = false;
}
};
$scope.changeScrypt = function(scrypt) {
// Protect params against changes
$scope.formData.scrypt = angular.copy(scrypt||{});
};
$scope.fileChanged = function(event) {
$scope.validatingFile = true;
$scope.formData.file = event && event.target && event.target.files && event.target.files.length && event.target.files[0];
if (!$scope.formData.file) {
$scope.validatingFile = false;
return;
}
$timeout(function() {
console.debug("[login] key file changed: ", $scope.formData.file);
$scope.validatingFile = true;
return CryptoUtils.readKeyFile($scope.formData.file, false/*withSecret*/)
.then(function(keypair) {
if (!keypair || !keypair.signPk) {
$scope.formData.file.valid = false;
$scope.formData.file.pubkey = undefined;
}
else {
$scope.formData.file.pubkey = CryptoUtils.util.encode_base58(keypair.signPk);
$scope.formData.file.valid = !$scope.expectedPubkey || $scope.expectedPubkey == $scope.formData.file.pubkey;
$scope.validatingFile = false;
}
})
.catch(function(err) {
$scope.validatingFile = false;
$scope.formData.file.valid = false;
$scope.formData.file.pubkey = undefined;
UIUtils.onError('ERROR.AUTH_FILE_ERROR')(err);
});
});
};
$scope.readFileContent = function(content) {
console.log(content);
};
$scope.removeKeyFile = function() {
$scope.formData.file = undefined;
};
// TODO : for DEV only
/*$timeout(function() {
$scope.formData = {
username: 'benoit.lavenier@e-is.pro',
password: ''
};
//$scope.form = {$valid:true};
}, 900);*/
}
function AuthModalController($scope, $controller, parameters) {
'ngInject';
parameters = parameters || {};
parameters.auth = true;
// Initialize the super class and extend it.
angular.extend(this, $controller('LoginModalCtrl', {$scope: $scope, parameters: parameters}));
}
/**
* Manage automatic authentication reset
* @param $scope
* @param $ionicHistory
* @param $state
* @param $q
* @param Idle
* @param UIUtils
* @param $ionicLoading
* @param csWallet
* @param csSettings
* @constructor
*/
function AuthIdleController($scope, $ionicHistory, $state, $q, Idle, UIUtils, $ionicLoading, csWallet, csSettings) {
'ngInject';
$scope.enableAuthIdle = false;
$scope.checkAuth = function(isAuth) {
isAuth = angular.isDefined(isAuth) ? isAuth : csWallet.isAuth();
var enable = csSettings.data.keepAuthIdle > 0 && csSettings.data.keepAuthIdle != 9999 && isAuth;
var changed = ($scope.enableAuthIdle != enable);
// need start/top watching
if (changed) {
// start idle
if (enable) {
console.debug("[app] Start auth idle (delay: {0}s)".format(csSettings.data.keepAuthIdle));
Idle.setIdle(csSettings.data.keepAuthIdle);
Idle.watch();
}
// stop idle, if need
else if ($scope.enableAuthIdle){
console.debug("[app] Stop auth idle");
Idle.unwatch();
}
$scope.enableAuthIdle = enable;
}
// if idle time changed: apply it
else if (enable && Idle.getIdle() !== csSettings.data.keepAuthIdle) {
console.debug("[app] Updating auth idle (delay: {0}s)".format(csSettings.data.keepAuthIdle));
Idle.setIdle(csSettings.data.keepAuthIdle);
}
};
csSettings.api.data.on.changed($scope, function() {
$scope.checkAuth();
});
// add listeners on wallet events
csWallet.api.data.on.login($scope, function(walletData, deferred) {
$scope.checkAuth();
return deferred ? deferred.resolve() : $q.when();
});
csWallet.api.data.on.auth($scope, function(walletData, deferred) {
$scope.checkAuth(true);
return deferred ? deferred.resolve() : $q.when();
});
csWallet.api.data.on.unauth($scope, function() {
$scope.checkAuth(false);
});
csWallet.api.data.on.logout($scope, function() {
$scope.checkAuth(false);
});
$scope.$on('IdleStart', function() {
if (!csSettings.data.rememberMe) {
$ionicLoading.hide(); // close previous toast
$ionicLoading.show({
template: "<div idle-countdown=\"countdown\" ng-init=\"countdown=5\">{{'LOGIN.AUTO_LOGOUT.IDLE_WARNING'|translate:{countdown:countdown} }}</div>"
});
}
});
$scope.$on('IdleEnd', function() {
if (!csSettings.data.rememberMe) {
$ionicLoading.hide();
}
});
$scope.$on('IdleTimeout', function() {
// Keep user login, but remove auth
if (csSettings.data.rememberMe) {
return csWallet.unauth()
.then(function () {
$ionicHistory.clearCache();
})
.catch(UIUtils.onError());
}
// Do not keep user login, so = logout
else {
return csWallet.logout()
.then(function () {
$ionicHistory.clearCache();
if ($state.current.data.auth === true) {
$ionicHistory.clearHistory();
return $scope.showHome();
}
})
.then(function () {
$ionicLoading.hide();
return UIUtils.alert.confirm('LOGIN.AUTO_LOGOUT.MESSAGE',
'LOGIN.AUTO_LOGOUT.TITLE', {
cancelText: 'COMMON.BTN_CLOSE',
okText: 'COMMON.BTN_LOGIN'
});
})
.then(function (relogin) {
if (relogin) {
return $scope.loginAndGo($state.current.name, $state.params,
{reload: true});
}
})
.catch(UIUtils.onError());
}
});
// Catch windows close event
window.addEventListener("beforeunload", function(e){
console.log("[auth idle] Getting event beforeunload");
return "Are you sure ?";
}, false);
}