feat: handle unprotected session expiration (#779)

* feat: hide note contents if the protection expires when the protected note is open and wasn't edited for a while

* feat: handle session expiration for opened protected note for both plain advanced editors

* fix: if after canceling  session expiry modal only one unprotected note stays selected, show its contents in the editor

* refactor: handle session expiration for opened protected note (move the logic to web client)

* feat: handle the case of selecting "Don't remember" option in session expiry dialog

* test (WIP): add unit tests for protecting opened note after the session has expired

* test: add remaining unit tests

* refactor: move the opened note protection logic to "editor_view"

* refactor: reviewer comments
- don't rely on user signed-in/out status to require authentication for protected note
- remove unnecessary async/awaits
- better wording on ui

* refactor: reviewer's comments:
 - use snjs method to check if "Don't remember" option is selected in authentication modal
 - move the constant to snjs
 - fix eslint error

* refactor: avoid `any` type for `appEvent` payload

* test: add unit tests

* chore: update function name

* refactor: use simpler protection session event types

* refactor: protected access terminology

* refactor: start counting idle timer after every edit (instead of counting by interval in spite of edits)

* test: unit tests

* style: don't give extra brightness to the "View Note"/"Authenticate" button on hover/focus

* chore: bump snjs version

* chore: put snjs "beta" version

* fix: run protection timeout when the note is marked as protected

* chore: snjs version bump

* refactor: immediately lock the note if it's marked as "Protected"

* refactor: rename component, directive and some props

* refactor: remove extra check

* refactor: rename the method

* chore: update snjs version

Co-authored-by: Mo Bitar <me@bitar.io>
This commit is contained in:
Vardan Hakobyan
2021-12-20 20:54:37 +04:00
committed by GitHub
parent eb4c8d0091
commit f120af3b43
29 changed files with 469 additions and 817 deletions

View File

@@ -28,7 +28,7 @@ export class NotesState {
top: 0,
left: 0,
};
contextMenuClickLocation: { x: number, y: number } = { x: 0, y: 0 };
contextMenuClickLocation: { x: number; y: number } = { x: 0, y: 0 };
contextMenuMaxHeight: number | 'auto' = 'auto';
showProtectedWarning = false;
@@ -185,7 +185,7 @@ export class NotesState {
this.contextMenuOpen = open;
}
setContextMenuClickLocation(location: { x: number, y: number }): void {
setContextMenuClickLocation(location: { x: number; y: number }): void {
this.contextMenuClickLocation = location;
}
@@ -212,7 +212,8 @@ export class NotesState {
// Open up-bottom is default behavior
let openUpBottom = true;
const bottomSpace = clientHeight - footerHeight - this.contextMenuClickLocation.y;
const bottomSpace =
clientHeight - footerHeight - this.contextMenuClickLocation.y;
const upSpace = this.contextMenuClickLocation.y;
// If not enough space to open up-bottom
@@ -220,26 +221,18 @@ export class NotesState {
// If there's enough space, open bottom-up
if (upSpace > maxContextMenuHeight) {
openUpBottom = false;
this.setContextMenuMaxHeight(
'auto'
);
// Else, reduce max height (menu will be scrollable) and open in whichever direction there's more space
this.setContextMenuMaxHeight('auto');
// Else, reduce max height (menu will be scrollable) and open in whichever direction there's more space
} else {
if (upSpace > bottomSpace) {
this.setContextMenuMaxHeight(
upSpace - 2
);
this.setContextMenuMaxHeight(upSpace - 2);
openUpBottom = false;
} else {
this.setContextMenuMaxHeight(
bottomSpace - 2
);
this.setContextMenuMaxHeight(bottomSpace - 2);
}
}
} else {
this.setContextMenuMaxHeight(
'auto'
);
this.setContextMenuMaxHeight('auto');
}
if (openUpBottom) {
@@ -375,9 +368,7 @@ export class NotesState {
const selectedNotes = Object.values(this.selectedNotes);
if (protect) {
await this.application.protectNotes(selectedNotes);
if (!this.application.hasProtectionSources()) {
this.setShowProtectedWarning(true);
}
this.setShowProtectedWarning(true);
} else {
await this.application.unprotectNotes(selectedNotes);
this.setShowProtectedWarning(false);

View File

@@ -1,6 +1,6 @@
import { ApplicationEvent } from "@standardnotes/snjs";
import { makeObservable, observable, action, runInAction } from "mobx";
import { WebApplication } from "../application";
import { ApplicationEvent } from '@standardnotes/snjs';
import { makeObservable, observable, action, runInAction } from 'mobx';
import { WebApplication } from '../application';
export class SearchOptionsState {
includeProtectedContents = false;
@@ -25,7 +25,10 @@ export class SearchOptionsState {
appObservers.push(
this.application.addEventObserver(async () => {
this.refreshIncludeProtectedContents();
}, ApplicationEvent.ProtectionSessionExpiryDateChanged)
}, ApplicationEvent.UnprotectedSessionBegan),
this.application.addEventObserver(async () => {
this.refreshIncludeProtectedContents();
}, ApplicationEvent.UnprotectedSessionExpired)
);
}
@@ -38,21 +41,17 @@ export class SearchOptionsState {
};
refreshIncludeProtectedContents = (): void => {
if (
this.includeProtectedContents &&
this.application.areProtectionsEnabled()
) {
this.includeProtectedContents = false;
}
this.includeProtectedContents =
this.application.hasUnprotectedAccessSession();
};
toggleIncludeProtectedContents = async (): Promise<void> => {
if (this.includeProtectedContents) {
this.includeProtectedContents = false;
} else {
const authorized = await this.application.authorizeSearchingProtectedNotesText();
await this.application.authorizeSearchingProtectedNotesText();
runInAction(() => {
this.includeProtectedContents = authorized;
this.refreshIncludeProtectedContents();
});
}
};