Autolock wip

This commit is contained in:
Mo Bitar
2018-11-13 15:05:57 -06:00
parent 9835992e16
commit 091f4cff7f
11 changed files with 258 additions and 119 deletions

View File

@@ -31,7 +31,8 @@ angular.module('app')
}
}
})
.controller('NotesCtrl', function (authManager, $timeout, $rootScope, modelManager, storageManager, desktopManager) {
.controller('NotesCtrl', function (authManager, $timeout, $rootScope, modelManager,
storageManager, desktopManager, privilegesManager) {
this.panelController = {};
@@ -198,19 +199,31 @@ angular.module('app')
}
}
this.selectNote = function(note, viaClick = false) {
this.selectNote = async function(note, viaClick = false) {
if(!note) {
this.createNewNote();
return;
}
this.selectedNote = note;
note.conflict_of = null; // clear conflict
this.selectionMade()(note);
this.selectedIndex = Math.max(this.visibleNotes().indexOf(note), 0);
let run = () => {
$timeout(() => {
this.selectedNote = note;
note.conflict_of = null; // clear conflict
this.selectionMade()(note);
this.selectedIndex = Math.max(this.visibleNotes().indexOf(note), 0);
if(viaClick && this.isFiltering()) {
desktopManager.searchText(this.noteFilter.text);
if(viaClick && this.isFiltering()) {
desktopManager.searchText(this.noteFilter.text);
}
})
}
if(note.locked && await privilegesManager.actionRequiresPrivilege(PrivilegesManager.ActionViewLockedNotes)) {
privilegesManager.presentPrivilegesModal(PrivilegesManager.ActionViewLockedNotes, () => {
run();
});
} else {
run();
}
}

View File

@@ -38,7 +38,6 @@ class AccountMenu {
}
$scope.canAddPasscode = !authManager.isEphemeralSession();
$scope.syncStatus = syncManager.syncStatus;
$scope.submitMfaForm = function() {
@@ -375,6 +374,24 @@ class AccountMenu {
Passcode Lock
*/
$scope.passcodeAutoLockOptions = passcodeManager.getAutoLockIntervalOptions();
$scope.reloadAutoLockInterval = function() {
passcodeManager.getAutoLockInterval().then((interval) => {
$timeout(() => {
$scope.selectedAutoLockInterval = interval;
console.log("selectedAutoLockInterval", $scope.selectedAutoLockInterval);
})
})
}
$scope.reloadAutoLockInterval();
$scope.selectAutoLockInterval = async function(interval) {
await passcodeManager.setAutoLockInterval(interval);
$scope.reloadAutoLockInterval();
}
$scope.hasPasscode = function() {
return passcodeManager.hasPasscode();
}

View File

@@ -5,7 +5,7 @@ class HttpManager extends SFHttpManager {
super($timeout);
this.setJWTRequestHandler(async () => {
return storageManager.getItem("jwt");;
return storageManager.getItem("jwt");
})
}
}

View File

@@ -1,112 +1,183 @@
angular.module('app')
.provider('passcodeManager', function () {
class PasscodeManager {
this.$get = function($rootScope, $timeout, modelManager, dbManager, authManager, storageManager) {
return new PasscodeManager($rootScope, $timeout, modelManager, dbManager, authManager, storageManager);
}
constructor(authManager, storageManager) {
document.addEventListener('visibilitychange', () => {
this.documentVisibilityChanged(document.visibilityState);
});
function PasscodeManager($rootScope, $timeout, modelManager, dbManager, authManager, storageManager) {
this.authManager = authManager;
this.storageManager = storageManager;
this._hasPasscode = storageManager.getItemSync("offlineParams", StorageManager.Fixed) != null;
this._hasPasscode = this.storageManager.getItemSync("offlineParams", StorageManager.Fixed) != null;
this._locked = this._hasPasscode;
this.isLocked = function() {
return this._locked;
}
const MillisecondsPerSecond = 1000;
PasscodeManager.AutoLockIntervalNone = 0;
PasscodeManager.AutoLockIntervalOneMinute = 60 * MillisecondsPerSecond;
PasscodeManager.AutoLockIntervalFiveMinutes = 300 * MillisecondsPerSecond;
PasscodeManager.AutoLockIntervalOneHour = 3600 * MillisecondsPerSecond;
this.hasPasscode = function() {
return this._hasPasscode;
}
PasscodeManager.AutoLockIntervalKey = "AutoLockIntervalKey";
}
this.keys = function() {
return this._keys;
}
this.passcodeAuthParams = function() {
var authParams = JSON.parse(storageManager.getItemSync("offlineParams", StorageManager.Fixed));
if(authParams && !authParams.version) {
var keys = this.keys();
if(keys && keys.ak) {
// If there's no version stored, and there's an ak, it has to be 002. Newer versions would have thier version stored in authParams.
authParams.version = "002";
} else {
authParams.version = "001";
}
getAutoLockIntervalOptions() {
return [
{
value: PasscodeManager.AutoLockIntervalNone,
label: "None"
},
{
value: PasscodeManager.AutoLockIntervalOneMinute,
label: "1 Min"
},
{
value: PasscodeManager.AutoLockIntervalFiveMinutes,
label: "5 Min"
},
{
value: PasscodeManager.AutoLockIntervalOneHour,
label: "1 Hr"
}
return authParams;
}
]
}
this.verifyPasscode = async function(passcode) {
return new Promise(async (resolve, reject) => {
var params = this.passcodeAuthParams();
let keys = await SFJS.crypto.computeEncryptionKeysForUser(passcode, params);
if(keys.pw !== params.hash) {
resolve(false);
} else {
resolve(true);
}
})
}
this.unlock = function(passcode, callback) {
var params = this.passcodeAuthParams();
SFJS.crypto.computeEncryptionKeysForUser(passcode, params).then((keys) => {
if(keys.pw !== params.hash) {
callback(false);
return;
}
this._keys = keys;
this._authParams = params;
this.decryptLocalStorage(keys, params).then(() => {
this._locked = false;
callback(true);
})
});
}
this.setPasscode = (passcode, callback) => {
var uuid = SFJS.crypto.generateUUIDSync();
SFJS.crypto.generateInitialKeysAndAuthParamsForUser(uuid, passcode).then((results) => {
let keys = results.keys;
let authParams = results.authParams;
authParams.hash = keys.pw;
this._keys = keys;
this._hasPasscode = true;
this._authParams = authParams;
// Encrypting will initially clear localStorage
this.encryptLocalStorage(keys, authParams);
// After it's cleared, it's safe to write to it
storageManager.setItem("offlineParams", JSON.stringify(authParams), StorageManager.Fixed);
callback(true);
});
}
this.changePasscode = (newPasscode, callback) => {
this.setPasscode(newPasscode, callback);
}
this.clearPasscode = function() {
storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.Fixed); // Transfer from Ephemeral
storageManager.removeItem("offlineParams", StorageManager.Fixed);
this._keys = null;
this._hasPasscode = false;
}
this.encryptLocalStorage = function(keys, authParams) {
storageManager.setKeys(keys, authParams);
// Switch to Ephemeral storage, wiping Fixed storage
// Last argument is `force`, which we set to true because in the case of changing passcode
storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.FixedEncrypted, true);
}
this.decryptLocalStorage = async function(keys, authParams) {
storageManager.setKeys(keys, authParams);
return storageManager.decryptStorage();
documentVisibilityChanged(visbility) {
let visible = document.visibilityState == "visible";
if(!visible) {
this.beginAutoLockTimer();
} else {
this.cancelAutoLockTimer();
}
}
});
async beginAutoLockTimer() {
console.log("beginAutoLockTimer");
var interval = await this.getAutoLockInterval();
this.lockTimeout = setTimeout(() => {
this.lockApplication();
}, interval);
}
cancelAutoLockTimer() {
console.log("cancelAutoLockTimer");
clearTimeout(this.lockTimeout);
}
lockApplication() {
console.log("lockApplication");
window.location.reload();
this.cancelAutoLockTimer();
}
isLocked() {
return this._locked;
}
hasPasscode() {
return this._hasPasscode;
}
keys() {
return this._keys;
}
async setAutoLockInterval(interval) {
console.log("Set autolock interval", interval);
return this.storageManager.setItem(PasscodeManager.AutoLockIntervalKey, JSON.stringify(interval), StorageManager.Fixed);
}
async getAutoLockInterval() {
let interval = await this.storageManager.getItem(PasscodeManager.AutoLockIntervalKey, StorageManager.Fixed);
console.log("Got interval", interval);
return interval && JSON.parse(interval);
}
passcodeAuthParams() {
var authParams = JSON.parse(this.storageManager.getItemSync("offlineParams", StorageManager.Fixed));
if(authParams && !authParams.version) {
var keys = this.keys();
if(keys && keys.ak) {
// If there's no version stored, and there's an ak, it has to be 002. Newer versions would have their version stored in authParams.
authParams.version = "002";
} else {
authParams.version = "001";
}
}
return authParams;
}
async verifyPasscode(passcode) {
return new Promise(async (resolve, reject) => {
var params = this.passcodeAuthParams();
let keys = await SFJS.crypto.computeEncryptionKeysForUser(passcode, params);
if(keys.pw !== params.hash) {
resolve(false);
} else {
resolve(true);
}
})
}
unlock(passcode, callback) {
var params = this.passcodeAuthParams();
SFJS.crypto.computeEncryptionKeysForUser(passcode, params).then((keys) => {
if(keys.pw !== params.hash) {
callback(false);
return;
}
this._keys = keys;
this._authParams = params;
this.decryptLocalStorage(keys, params).then(() => {
this._locked = false;
callback(true);
})
});
}
setPasscode(passcode, callback) {
var uuid = SFJS.crypto.generateUUIDSync();
SFJS.crypto.generateInitialKeysAndAuthParamsForUser(uuid, passcode).then((results) => {
let keys = results.keys;
let authParams = results.authParams;
authParams.hash = keys.pw;
this._keys = keys;
this._hasPasscode = true;
this._authParams = authParams;
// Encrypting will initially clear localStorage
this.encryptLocalStorage(keys, authParams);
// After it's cleared, it's safe to write to it
this.storageManager.setItem("offlineParams", JSON.stringify(authParams), StorageManager.Fixed);
callback(true);
});
}
changePasscode(newPasscode, callback) {
this.setPasscode(newPasscode, callback);
}
clearPasscode() {
this.storageManager.setItemsMode(this.authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.Fixed); // Transfer from Ephemeral
this.storageManager.removeItem("offlineParams", StorageManager.Fixed);
this._keys = null;
this._hasPasscode = false;
}
encryptLocalStorage(keys, authParams) {
this.storageManager.setKeys(keys, authParams);
// Switch to Ephemeral storage, wiping Fixed storage
// Last argument is `force`, which we set to true because in the case of changing passcode
this.storageManager.setItemsMode(this.authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.FixedEncrypted, true);
}
async decryptLocalStorage(keys, authParams) {
this.storageManager.setKeys(keys, authParams);
return this.storageManager.decryptStorage();
}
}
angular.module('app').service('passcodeManager', PasscodeManager);

View File

@@ -15,10 +15,14 @@ class PrivilegesManager {
PrivilegesManager.ActionManageExtensions = "ActionManageExtensions";
PrivilegesManager.ActionDownloadBackup = "ActionDownloadBackup";
PrivilegesManager.ActionViewLockedNotes = "ActionViewLockedNotes";
PrivilegesManager.ActionManagePrivileges = "ActionManagePrivileges";
this.availableActions = [
PrivilegesManager.ActionManageExtensions,
PrivilegesManager.ActionDownloadBackup
PrivilegesManager.ActionDownloadBackup,
PrivilegesManager.ActionViewLockedNotes,
PrivilegesManager.ActionManagePrivileges
]
this.availableCredentials = [
@@ -119,10 +123,19 @@ class PrivilegesManager {
metadata[PrivilegesManager.ActionManageExtensions] = {
label: "Manage Extensions"
}
metadata[PrivilegesManager.ActionDownloadBackup] = {
label: "Download Backups"
};
metadata[PrivilegesManager.ActionViewLockedNotes] = {
label: "View Locked Notes"
};
metadata[PrivilegesManager.ActionManagePrivileges] = {
label: "Manage Privileges"
}
return metadata[action];
}