refactor: remove privileges in favor of SNJS protections
This commit is contained in:
@@ -44,8 +44,6 @@ import {
|
|||||||
PanelResizer,
|
PanelResizer,
|
||||||
PasswordWizard,
|
PasswordWizard,
|
||||||
PermissionsModal,
|
PermissionsModal,
|
||||||
PrivilegesAuthModal,
|
|
||||||
PrivilegesManagementModal,
|
|
||||||
RevisionPreviewModal,
|
RevisionPreviewModal,
|
||||||
HistoryMenu,
|
HistoryMenu,
|
||||||
SyncResolutionMenu,
|
SyncResolutionMenu,
|
||||||
@@ -140,11 +138,6 @@ const startApplication: StartApplication = async function startApplication(
|
|||||||
.directive('panelResizer', () => new PanelResizer())
|
.directive('panelResizer', () => new PanelResizer())
|
||||||
.directive('passwordWizard', () => new PasswordWizard())
|
.directive('passwordWizard', () => new PasswordWizard())
|
||||||
.directive('permissionsModal', () => new PermissionsModal())
|
.directive('permissionsModal', () => new PermissionsModal())
|
||||||
.directive('privilegesAuthModal', () => new PrivilegesAuthModal())
|
|
||||||
.directive(
|
|
||||||
'privilegesManagementModal',
|
|
||||||
() => new PrivilegesManagementModal()
|
|
||||||
)
|
|
||||||
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
|
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
|
||||||
.directive('historyMenu', () => new HistoryMenu())
|
.directive('historyMenu', () => new HistoryMenu())
|
||||||
.directive('syncResolutionMenu', () => new SyncResolutionMenu())
|
.directive('syncResolutionMenu', () => new SyncResolutionMenu())
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ export { MenuRow } from './menuRow';
|
|||||||
export { PanelResizer } from './panelResizer';
|
export { PanelResizer } from './panelResizer';
|
||||||
export { PasswordWizard } from './passwordWizard';
|
export { PasswordWizard } from './passwordWizard';
|
||||||
export { PermissionsModal } from './permissionsModal';
|
export { PermissionsModal } from './permissionsModal';
|
||||||
export { PrivilegesAuthModal } from './privilegesAuthModal';
|
|
||||||
export { PrivilegesManagementModal } from './privilegesManagementModal';
|
|
||||||
export { RevisionPreviewModal } from './revisionPreviewModal';
|
export { RevisionPreviewModal } from './revisionPreviewModal';
|
||||||
export { HistoryMenu } from './historyMenu';
|
export { HistoryMenu } from './historyMenu';
|
||||||
export { SyncResolutionMenu } from './syncResolutionMenu';
|
export { SyncResolutionMenu } from './syncResolutionMenu';
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
import { WebDirective } from './../../types';
|
|
||||||
import { WebApplication } from '@/ui_models/application';
|
|
||||||
import { ProtectedAction, PrivilegeCredential, PrivilegeSessionLength } from '@standardnotes/snjs';
|
|
||||||
import template from '%/directives/privileges-auth-modal.pug';
|
|
||||||
|
|
||||||
type PrivilegesAuthModalScope = {
|
|
||||||
application: WebApplication
|
|
||||||
action: ProtectedAction
|
|
||||||
onSuccess: () => void
|
|
||||||
onCancel: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
class PrivilegesAuthModalCtrl implements PrivilegesAuthModalScope {
|
|
||||||
$element: JQLite
|
|
||||||
$timeout: ng.ITimeoutService
|
|
||||||
application!: WebApplication
|
|
||||||
action!: ProtectedAction
|
|
||||||
onSuccess!: () => void
|
|
||||||
onCancel!: () => void
|
|
||||||
authParameters: Partial<Record<PrivilegeCredential, string>> = {}
|
|
||||||
sessionLengthOptions!: { value: PrivilegeSessionLength, label: string }[]
|
|
||||||
selectedSessionLength!: PrivilegeSessionLength
|
|
||||||
requiredCredentials!: PrivilegeCredential[]
|
|
||||||
failedCredentials!: PrivilegeCredential[]
|
|
||||||
|
|
||||||
/* @ngInject */
|
|
||||||
constructor(
|
|
||||||
$element: JQLite,
|
|
||||||
$timeout: ng.ITimeoutService
|
|
||||||
) {
|
|
||||||
this.$element = $element;
|
|
||||||
this.$timeout = $timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
$onInit() {
|
|
||||||
this.sessionLengthOptions = this.application!.privilegesService!
|
|
||||||
.getSessionLengthOptions();
|
|
||||||
this.application.privilegesService!.getSelectedSessionLength()
|
|
||||||
.then((length) => {
|
|
||||||
this.$timeout(() => {
|
|
||||||
this.selectedSessionLength = length;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.application.privilegesService!.netCredentialsForAction(this.action)
|
|
||||||
.then((credentials) => {
|
|
||||||
this.$timeout(() => {
|
|
||||||
this.requiredCredentials = credentials.sort();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
selectSessionLength(length: PrivilegeSessionLength) {
|
|
||||||
this.selectedSessionLength = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
promptForCredential(credential: PrivilegeCredential) {
|
|
||||||
return this.application.privilegesService!.displayInfoForCredential(credential).prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dismiss();
|
|
||||||
this.onCancel && this.onCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
isCredentialInFailureState(credential: PrivilegeCredential) {
|
|
||||||
if (!this.failedCredentials) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.failedCredentials.find((candidate) => {
|
|
||||||
return candidate === credential;
|
|
||||||
}) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
validate() {
|
|
||||||
const failed = [];
|
|
||||||
for (const cred of this.requiredCredentials) {
|
|
||||||
const value = this.authParameters[cred];
|
|
||||||
if (!value || value.length === 0) {
|
|
||||||
failed.push(cred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.failedCredentials = failed;
|
|
||||||
return failed.length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async submit() {
|
|
||||||
if (!this.validate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const result = await this.application.privilegesService!.authenticateAction(
|
|
||||||
this.action,
|
|
||||||
this.authParameters
|
|
||||||
);
|
|
||||||
this.$timeout(() => {
|
|
||||||
if (result.success) {
|
|
||||||
this.application.privilegesService!.setSessionLength(this.selectedSessionLength);
|
|
||||||
this.onSuccess();
|
|
||||||
this.dismiss();
|
|
||||||
} else {
|
|
||||||
this.failedCredentials = result.failedCredentials;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss() {
|
|
||||||
const elem = this.$element;
|
|
||||||
const scope = elem.scope();
|
|
||||||
scope.$destroy();
|
|
||||||
elem.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PrivilegesAuthModal extends WebDirective {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.restrict = 'E';
|
|
||||||
this.template = template;
|
|
||||||
this.controller = PrivilegesAuthModalCtrl;
|
|
||||||
this.controllerAs = 'ctrl';
|
|
||||||
this.bindToController = true;
|
|
||||||
this.scope = {
|
|
||||||
action: '=',
|
|
||||||
onSuccess: '=',
|
|
||||||
onCancel: '=',
|
|
||||||
application: '='
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
import { WebDirective } from './../../types';
|
|
||||||
import { WebApplication } from '@/ui_models/application';
|
|
||||||
import template from '%/directives/privileges-management-modal.pug';
|
|
||||||
import { PrivilegeCredential, ProtectedAction, SNPrivileges, PrivilegeSessionLength } from '@standardnotes/snjs';
|
|
||||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
|
||||||
import { PrivilegeMutator } from '@standardnotes/snjs';
|
|
||||||
|
|
||||||
type DisplayInfo = {
|
|
||||||
label: string
|
|
||||||
prompt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
class PrivilegesManagementModalCtrl extends PureViewCtrl {
|
|
||||||
|
|
||||||
hasPasscode = false
|
|
||||||
hasAccount = false
|
|
||||||
$element: JQLite
|
|
||||||
application!: WebApplication
|
|
||||||
privileges!: SNPrivileges
|
|
||||||
availableActions!: ProtectedAction[]
|
|
||||||
availableCredentials!: PrivilegeCredential[]
|
|
||||||
sessionExpirey!: string
|
|
||||||
sessionExpired = true
|
|
||||||
credentialDisplayInfo: Partial<Record<PrivilegeCredential, DisplayInfo>> = {}
|
|
||||||
onCancel!: () => void
|
|
||||||
|
|
||||||
/* @ngInject */
|
|
||||||
constructor(
|
|
||||||
$timeout: ng.ITimeoutService,
|
|
||||||
$element: JQLite
|
|
||||||
) {
|
|
||||||
super($timeout);
|
|
||||||
this.$element = $element;
|
|
||||||
}
|
|
||||||
|
|
||||||
async onAppLaunch() {
|
|
||||||
super.onAppLaunch();
|
|
||||||
this.hasPasscode = this.application.hasPasscode();
|
|
||||||
this.hasAccount = !this.application.noAccount();
|
|
||||||
this.reloadPrivileges();
|
|
||||||
}
|
|
||||||
|
|
||||||
displayInfoForCredential(credential: PrivilegeCredential) {
|
|
||||||
const info: any = this.application.privilegesService!.displayInfoForCredential(credential);
|
|
||||||
if (credential === PrivilegeCredential.LocalPasscode) {
|
|
||||||
info.availability = this.hasPasscode;
|
|
||||||
} else if (credential === PrivilegeCredential.AccountPassword) {
|
|
||||||
info.availability = this.hasAccount;
|
|
||||||
} else {
|
|
||||||
info.availability = true;
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
displayInfoForAction(action: ProtectedAction) {
|
|
||||||
return this.application.privilegesService!.displayInfoForAction(action).label;
|
|
||||||
}
|
|
||||||
|
|
||||||
isCredentialRequiredForAction(action: ProtectedAction, credential: PrivilegeCredential) {
|
|
||||||
if (!this.privileges) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.privileges.isCredentialRequiredForAction(action, credential);
|
|
||||||
}
|
|
||||||
|
|
||||||
async clearSession() {
|
|
||||||
await this.application.privilegesService!.clearSession();
|
|
||||||
this.reloadPrivileges();
|
|
||||||
}
|
|
||||||
|
|
||||||
async reloadPrivileges() {
|
|
||||||
this.availableActions = this.application.privilegesService!.getAvailableActions();
|
|
||||||
this.availableCredentials = this.application.privilegesService!.getAvailableCredentials();
|
|
||||||
const sessionEndDate = await this.application.privilegesService!.getSessionExpirey();
|
|
||||||
this.sessionExpirey = sessionEndDate.toLocaleString();
|
|
||||||
this.sessionExpired = new Date() >= sessionEndDate;
|
|
||||||
for (const cred of this.availableCredentials) {
|
|
||||||
this.credentialDisplayInfo[cred] = this.displayInfoForCredential(cred);
|
|
||||||
}
|
|
||||||
const privs = await this.application.privilegesService!.getPrivileges();
|
|
||||||
this.$timeout(() => {
|
|
||||||
this.privileges = privs;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkboxValueChanged(action: ProtectedAction, credential: PrivilegeCredential) {
|
|
||||||
this.application.changeAndSaveItem(this.privileges.uuid, (m) => {
|
|
||||||
const mutator = m as PrivilegeMutator;
|
|
||||||
mutator.toggleCredentialForAction(action, credential);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.dismiss();
|
|
||||||
this.onCancel && this.onCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss() {
|
|
||||||
const elem = this.$element;
|
|
||||||
const scope = elem.scope();
|
|
||||||
scope.$destroy();
|
|
||||||
elem.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PrivilegesManagementModal extends WebDirective {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.restrict = 'E';
|
|
||||||
this.template = template;
|
|
||||||
this.controller = PrivilegesManagementModalCtrl;
|
|
||||||
this.controllerAs = 'ctrl';
|
|
||||||
this.bindToController = true;
|
|
||||||
this.scope = {
|
|
||||||
application: '='
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
RemoteSession,
|
RemoteSession,
|
||||||
SessionStrings,
|
SessionStrings,
|
||||||
UuidString,
|
UuidString,
|
||||||
|
isNullOrUndefined,
|
||||||
} from '@standardnotes/snjs';
|
} from '@standardnotes/snjs';
|
||||||
import { autorun, IAutorunOptions, IReactionPublic } from 'mobx';
|
import { autorun, IAutorunOptions, IReactionPublic } from 'mobx';
|
||||||
import { render, FunctionComponent } from 'preact';
|
import { render, FunctionComponent } from 'preact';
|
||||||
@@ -78,7 +79,9 @@ function useSessions(
|
|||||||
setSessions(sessionsDuringRevoke);
|
setSessions(sessionsDuringRevoke);
|
||||||
|
|
||||||
const response = await responsePromise;
|
const response = await responsePromise;
|
||||||
if ('error' in response) {
|
if (isNullOrUndefined(response)) {
|
||||||
|
setSessions(sessionsBeforeRevoke);
|
||||||
|
} else if ('error' in response) {
|
||||||
if (response.error?.message) {
|
if (response.error?.message) {
|
||||||
setErrorMessage(response.error?.message);
|
setErrorMessage(response.error?.message);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { WebApplication } from '@/ui_models/application';
|
import { WebApplication } from '@/ui_models/application';
|
||||||
import { EncryptionIntent, ProtectedAction, SNItem, ContentType, SNNote, BackupFile } from '@standardnotes/snjs';
|
import {
|
||||||
|
EncryptionIntent,
|
||||||
|
ContentType,
|
||||||
|
SNNote,
|
||||||
|
BackupFile
|
||||||
|
} from '@standardnotes/snjs';
|
||||||
|
|
||||||
function zippableTxtName(name: string, suffix = ""): string {
|
function zippableTxtName(name: string, suffix = ""): string {
|
||||||
const sanitizedName = name
|
const sanitizedName = name
|
||||||
@@ -22,41 +27,26 @@ export class ArchiveManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async downloadBackup(encrypted: boolean) {
|
public async downloadBackup(encrypted: boolean) {
|
||||||
const run = async () => {
|
const intent = encrypted
|
||||||
const intent = encrypted
|
? EncryptionIntent.FileEncrypted
|
||||||
? EncryptionIntent.FileEncrypted
|
: EncryptionIntent.FileDecrypted;
|
||||||
: EncryptionIntent.FileDecrypted;
|
|
||||||
|
|
||||||
const data = await this.application.createBackupFile(intent);
|
const data = await this.application.createBackupFile(intent);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const blobData = new Blob(
|
const blobData = new Blob(
|
||||||
[JSON.stringify(data, null, 2)],
|
[JSON.stringify(data, null, 2)],
|
||||||
{ type: 'text/json' }
|
{ type: 'text/json' }
|
||||||
|
);
|
||||||
|
if (encrypted) {
|
||||||
|
this.downloadData(
|
||||||
|
blobData,
|
||||||
|
`Standard Notes Encrypted Backup and Import File - ${this.formattedDate()}.txt`
|
||||||
);
|
);
|
||||||
if (encrypted) {
|
|
||||||
this.downloadData(
|
|
||||||
blobData,
|
|
||||||
`Standard Notes Encrypted Backup and Import File - ${this.formattedDate()}.txt`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
/** download as zipped plain text files */
|
|
||||||
this.downloadZippedDecryptedItems(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
await this.application.privilegesService!
|
|
||||||
.actionRequiresPrivilege(ProtectedAction.ManageBackups)
|
|
||||||
) {
|
|
||||||
this.application.presentPrivilegesModal(
|
|
||||||
ProtectedAction.ManageBackups,
|
|
||||||
() => {
|
|
||||||
run();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
run();
|
/** download as zipped plain text files */
|
||||||
|
this.downloadZippedDecryptedItems(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ export class AppState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openEditor(noteUuid: string) {
|
async openEditor(noteUuid: string): Promise<void> {
|
||||||
if (this.getActiveEditor()?.note?.uuid === noteUuid) {
|
if (this.getActiveEditor()?.note?.uuid === noteUuid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ export class AppState {
|
|||||||
if (!note) {
|
if (!note) {
|
||||||
console.warn('Tried accessing a non-existant note of UUID ' + noteUuid);
|
console.warn('Tried accessing a non-existant note of UUID ' + noteUuid);
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (await this.application.authorizeNoteAccess(note)) {
|
if (await this.application.authorizeNoteAccess(note)) {
|
||||||
const activeEditor = this.getActiveEditor();
|
const activeEditor = this.getActiveEditor();
|
||||||
|
|||||||
@@ -80,8 +80,7 @@
|
|||||||
)
|
)
|
||||||
menu-row(
|
menu-row(
|
||||||
action='self.selectedMenuItem(true); self.toggleProtectNote()'
|
action='self.selectedMenuItem(true); self.toggleProtectNote()'
|
||||||
desc=`'Protecting a note will require credentials to view
|
desc=`'Protecting a note will require credentials to view it'`,
|
||||||
it (Manage Privileges via Account menu)'`,
|
|
||||||
label="self.note.protected ? 'Unprotect' : 'Protect'"
|
label="self.note.protected ? 'Unprotect' : 'Protect'"
|
||||||
)
|
)
|
||||||
menu-row(
|
menu-row(
|
||||||
|
|||||||
@@ -42,55 +42,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#privileges-modal {
|
|
||||||
min-width: 400px;
|
|
||||||
max-width: 700px;
|
|
||||||
|
|
||||||
.sk-panel-header {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
padding: 1.1rem 2rem;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
width: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0px;
|
|
||||||
border-color: var(--sn-stylekit-contrast-border-color);
|
|
||||||
background-color: var(--sn-stylekit-background-color);
|
|
||||||
color: var(--sn-stylekit-contrast-foreground-color);
|
|
||||||
|
|
||||||
th,
|
|
||||||
td {
|
|
||||||
padding: 6px 13px;
|
|
||||||
border: 1px solid var(--sn-stylekit-contrast-border-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:nth-child(2n) {
|
|
||||||
background-color: var(--sn-stylekit-contrast-background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: center;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.priv-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#item-preview-modal {
|
#item-preview-modal {
|
||||||
> .sk-modal-content {
|
> .sk-modal-content {
|
||||||
width: 800px;
|
width: 800px;
|
||||||
|
|||||||
@@ -222,10 +222,6 @@
|
|||||||
| {{option.label}}
|
| {{option.label}}
|
||||||
.sk-p The autolock timer begins when the window or tab loses focus.
|
.sk-p The autolock timer begins when the window or tab loses focus.
|
||||||
.sk-panel-row
|
.sk-panel-row
|
||||||
a.sk-a.info.sk-panel-row.condensed(
|
|
||||||
ng-click="self.openPrivilegesModal('')",
|
|
||||||
ng-show='!self.state.user'
|
|
||||||
) Manage Privileges
|
|
||||||
a.sk-a.info.sk-panel-row.condensed(
|
a.sk-a.info.sk-panel-row.condensed(
|
||||||
ng-click='self.changePasscodePressed()'
|
ng-click='self.changePasscodePressed()'
|
||||||
) Change Passcode
|
) Change Passcode
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
.sk-modal-background(ng-click="ctrl.cancel()")
|
|
||||||
#privileges-modal.sk-modal-content
|
|
||||||
.sn-component
|
|
||||||
.sk-panel
|
|
||||||
.sk-panel-header
|
|
||||||
.sk-panel-header-title Authentication Required
|
|
||||||
a.close-button.info(ng-click="ctrl.cancel()") Cancel
|
|
||||||
.sk-panel-content
|
|
||||||
.sk-panel-section
|
|
||||||
div(ng-repeat="credential in ctrl.requiredCredentials")
|
|
||||||
.sk-p.sk-bold.sk-panel-row
|
|
||||||
strong {{ctrl.promptForCredential(credential)}}
|
|
||||||
.sk-panel-row
|
|
||||||
input.sk-input.contrast(
|
|
||||||
ng-model="ctrl.authParameters[credential]"
|
|
||||||
should-focus="$index == 0"
|
|
||||||
sn-autofocus="true"
|
|
||||||
sn-enter="ctrl.submit()"
|
|
||||||
type="password"
|
|
||||||
)
|
|
||||||
.sk-panel-row
|
|
||||||
label.sk-label.danger(
|
|
||||||
ng-if="ctrl.isCredentialInFailureState(credential)"
|
|
||||||
) Invalid authentication. Please try again.
|
|
||||||
.sk-panel-row
|
|
||||||
.sk-panel-row
|
|
||||||
.sk-horizontal-group
|
|
||||||
.sk-p.sk-bold Remember For
|
|
||||||
a.sk-a.info(
|
|
||||||
ng-repeat="option in ctrl.sessionLengthOptions"
|
|
||||||
ng-class="{'boxed' : option.value == ctrl.selectedSessionLength}"
|
|
||||||
ng-click="ctrl.selectSessionLength(option.value)"
|
|
||||||
)
|
|
||||||
| {{option.label}}
|
|
||||||
.sk-panel-footer.extra-padding
|
|
||||||
.sk-button.info.big.block.bold(ng-click="ctrl.submit()")
|
|
||||||
.sk-label Submit
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
.sk-modal-background(ng-click='ctrl.cancel()')
|
|
||||||
#privileges-modal.sk-modal-content
|
|
||||||
.sn-component
|
|
||||||
.sk-panel
|
|
||||||
.sk-panel-header
|
|
||||||
.sk-panel-header-title Manage Privileges
|
|
||||||
a.sk-a.close-button.info(ng-click='ctrl.cancel()') Done
|
|
||||||
.sk-panel-content
|
|
||||||
.sk-panel-section
|
|
||||||
table.sk-table
|
|
||||||
thead
|
|
||||||
tr
|
|
||||||
th
|
|
||||||
th(ng-repeat='cred in ctrl.availableCredentials')
|
|
||||||
.priv-header
|
|
||||||
strong {{ctrl.credentialDisplayInfo[cred].label}}
|
|
||||||
.sk-p.font-small(
|
|
||||||
ng-show='!ctrl.credentialDisplayInfo[cred].availability',
|
|
||||||
style='margin-top: 2px'
|
|
||||||
) Not Configured
|
|
||||||
tbody
|
|
||||||
tr(ng-repeat='action in ctrl.availableActions')
|
|
||||||
td
|
|
||||||
.sk-p {{ctrl.displayInfoForAction(action)}}
|
|
||||||
th(ng-repeat='credential in ctrl.availableCredentials')
|
|
||||||
input(
|
|
||||||
ng-checked='ctrl.isCredentialRequiredForAction(action, credential)',
|
|
||||||
ng-click='ctrl.checkboxValueChanged(action, credential)',
|
|
||||||
ng-disabled='!ctrl.credentialDisplayInfo[credential].availability',
|
|
||||||
type='checkbox'
|
|
||||||
)
|
|
||||||
.sk-panel-section(ng-if='ctrl.sessionExpirey && !ctrl.sessionExpired')
|
|
||||||
.sk-p.sk-panel-row
|
|
||||||
| You will not be asked to authenticate until {{ctrl.sessionExpirey}}.
|
|
||||||
a.sk-a.sk-panel-row.info(ng-click='ctrl.clearSession()') Clear Session
|
|
||||||
.sk-panel-footer
|
|
||||||
.sk-h2.sk-bold About Privileges
|
|
||||||
.sk-panel-section.no-bottom-pad
|
|
||||||
.sk-panel-row
|
|
||||||
.text-content
|
|
||||||
.sk-p
|
|
||||||
| Privileges represent interface level authentication for accessing
|
|
||||||
| certain items and features. Note that when your application is unlocked,
|
|
||||||
| your data exists in temporary memory in an unencrypted state.
|
|
||||||
| Privileges are meant to protect against unwanted access in the event of
|
|
||||||
| an unlocked application, but do not affect data encryption state.
|
|
||||||
p.sk-p
|
|
||||||
| Privileges sync across your other devices; however, note that if you
|
|
||||||
| require an "Application Passcode" privilege, and another device does not have
|
|
||||||
| an application passcode set up, the application passcode requirement will be ignored
|
|
||||||
| on that device.
|
|
||||||
Reference in New Issue
Block a user