Skip to content
This repository has been archived by the owner on Jun 20, 2022. It is now read-only.

Commit

Permalink
fix: clear all storage data when signing out
Browse files Browse the repository at this point in the history
  • Loading branch information
arielsvg committed Mar 24, 2021
1 parent b58efd8 commit c6d4ffd
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 103 deletions.
178 changes: 85 additions & 93 deletions app/javascripts/main/window.ts
Expand Up @@ -51,13 +51,82 @@ export async function createWindowState({
}): Promise<WindowState> {
const window = await createWindow(appState.store);
const services = createWindowServices(window, appState, appLocale);
registerWindowEventListeners({
shell,
appState,
window,
backupsManager: services.backupsManager,
trayManager: services.trayManager,
onClosed: teardown,

const shouldOpenUrl = (url: string) =>
url.startsWith('http') || url.startsWith('mailto');

window.on('closed', teardown);

window.on('show', () => {
checkForUpdate(appState, appState.updates, false);
});

window.on('focus', () => {
window.webContents.send(IpcMessages.WindowFocused, null);
});

window.on('blur', () => {
window.webContents.send(IpcMessages.WindowBlurred, null);
services.backupsManager.applicationDidBlur();
});

window.once('ready-to-show', () => {
window.show();
});

window.webContents.on('ipc-message', async (_event, message) => {
if (message === IpcMessages.SigningOut) {
await window.webContents.session.clearStorageData();
window.webContents.session.flushStorageData();
}
});

window.on('close', (event) => {
if (
!appState.willQuitApp &&
(isMac() || services.trayManager.shouldMinimizeToTray())
) {
/**
* On MacOS, closing a window does not quit the app. On Window and Linux,
* it only does if you haven't enabled minimize to tray.
*/
event.preventDefault();
/**
* Handles Mac full screen issue where pressing close results
* in a black screen.
*/
if (window.isFullScreen()) {
window.setFullScreen(false);
}
window.hide();
}
});

/** handle link clicks */
window.webContents.on('new-window', (event, url) => {
if (shouldOpenUrl(url)) {
shell.openExternal(url);
}
event.preventDefault();
});

/**
* handle link clicks (this event is fired instead of 'new-window' when
* target is not set to _blank)
*/
window.webContents.on('will-navigate', (event, url) => {
/** Check for windowUrl equality in the case of window.reload() calls. */
if (fileUrlsAreEqual(url, appState.startUrl)) {
return;
}
if (shouldOpenUrl(url)) {
shell.openExternal(url);
}
event.preventDefault();
});

window.webContents.on('context-menu', (_event, params) => {
buildContextMenu(window.webContents, params).popup();
});

return {
Expand Down Expand Up @@ -98,6 +167,15 @@ async function createWindow(store: Store): Promise<Electron.BrowserWindow> {
handle(MessageType.SpellCheckerLanguages, () =>
window.webContents.session.getSpellCheckerLanguages()
);
handle(MessageType.SetLocalStorageValue, async (key, value) => {
await window.webContents.executeJavaScript(
`localStorage.setItem("${key}", "${value}")`
);
window.webContents.session.flushStorageData();
});
handle(MessageType.ExecuteJavaScript, (code) =>
window.webContents.executeJavaScript(code)
);
window.webContents.once('did-finish-load', () => {
send(AppMessageType.WindowLoaded);
});
Expand Down Expand Up @@ -171,92 +249,6 @@ function fileUrlsAreEqual(a: string, b: string): boolean {
}
}

function registerWindowEventListeners({
shell,
appState,
window,
backupsManager,
trayManager,
onClosed,
}: {
shell: Shell;
appState: AppState;
window: Electron.BrowserWindow;
backupsManager: BackupsManager;
trayManager: TrayManager;
onClosed: () => void;
}) {
const shouldOpenUrl = (url: string) =>
url.startsWith('http') || url.startsWith('mailto');

window.on('closed', onClosed);

window.on('show', () => {
checkForUpdate(appState, appState.updates, false);
});

window.on('focus', () => {
window.webContents.send(IpcMessages.WindowFocused, null);
});

window.on('blur', () => {
window.webContents.send(IpcMessages.WindowBlurred, null);
backupsManager.applicationDidBlur();
});

window.once('ready-to-show', () => {
window.show();
});

window.on('close', (event) => {
if (
!appState.willQuitApp &&
(isMac() || trayManager.shouldMinimizeToTray())
) {
/**
* On MacOS, closing a window does not quit the app. On Window and Linux,
* it only does if you haven't enabled minimize to tray.
*/
event.preventDefault();
/**
* Handles Mac full screen issue where pressing close results
* in a black screen.
*/
if (window.isFullScreen()) {
window.setFullScreen(false);
}
window.hide();
}
});

/** handle link clicks */
window.webContents.on('new-window', (event, url) => {
if (shouldOpenUrl(url)) {
shell.openExternal(url);
}
event.preventDefault();
});

/**
* handle link clicks (this event is fired instead of 'new-window' when
* target is not set to _blank)
*/
window.webContents.on('will-navigate', (event, url) => {
/** Check for windowUrl equality in the case of window.reload() calls. */
if (fileUrlsAreEqual(url, appState.startUrl)) {
return;
}
if (shouldOpenUrl(url)) {
shell.openExternal(url);
}
event.preventDefault();
});

window.webContents.on('context-menu', (_event, params) => {
buildContextMenu(window.webContents, params).popup();
});
}

interface WindowPosition {
bounds: Rectangle;
isMaximized: boolean;
Expand Down
8 changes: 6 additions & 2 deletions app/javascripts/renderer/renderer.ts
Expand Up @@ -17,6 +17,7 @@ declare global {
electronAppVersion: string;
zip: any;
startApplication: StartApplication;
bridge: Bridge;
}
}

Expand All @@ -37,11 +38,11 @@ window._bugsnag_api_key = BUGSNAG_API_KEY;

await configureWindow(mainThread);

const webBridge = await createWebBridge(mainThread);
window.bridge = await createWebBridge(mainThread);
window.startApplication(
// eslint-disable-next-line no-undef
DEFAULT_SYNC_SERVER || 'https://sync.standardnotes.org',
webBridge
window.bridge
);

await new Promise((resolve) =>
Expand Down Expand Up @@ -127,6 +128,9 @@ async function createWebBridge(mainThread: any): Promise<Bridge> {
onInitialDataLoad() {
mainThread.sendIpcMessage(IpcMessages.InitialDataLoaded, {});
},
onSignOut() {
mainThread.sendIpcMessage(IpcMessages.SigningOut, {});
},
async downloadBackup() {
const desktopManager = window.desktopManager;
desktopManager.desktop_didBeginBackup();
Expand Down
1 change: 1 addition & 0 deletions app/javascripts/shared/ipcMessages.ts
Expand Up @@ -17,4 +17,5 @@ export enum IpcMessages {
Quit = 'Quit',
UseLocalstorageForKeychain = 'UseLocalstorageForKeychain',
LearnMoreAboutKeychainAccess = 'LearnMoreAboutKeychainAccess',
SigningOut = 'SigningOut',
}
2 changes: 2 additions & 0 deletions test/TestIpcMessage.ts
Expand Up @@ -26,6 +26,7 @@ export enum MessageType {
StoreData,
StoreSettingsLocation,
StoreSet,
SetLocalStorageValue,
AppMenuItems,
SpellCheckerManager,
SpellCheckerLanguages,
Expand All @@ -46,4 +47,5 @@ export enum MessageType {
AutoUpdateEnabled,
HasReloadedMenu,
AppStateCall,
ExecuteJavaScript,
}
9 changes: 8 additions & 1 deletion test/driver.ts
Expand Up @@ -110,7 +110,12 @@ class Driver {
appStateCall = (methodName: string, ...args: any): Promise<any> =>
this.send(MessageType.AppStateCall, methodName, ...args);

readonly store = {
readonly window = {
executeJavascript: (code: string): Promise<unknown> =>
this.send(MessageType.ExecuteJavaScript, code),
};

readonly storage = {
dataOnDisk: async (): Promise<{ [key in StoreKeys]: any }> => {
const location = await this.send(MessageType.StoreSettingsLocation);
return readJSONFile(location);
Expand All @@ -119,6 +124,8 @@ class Driver {
this.send(MessageType.StoreSettingsLocation),
setZoomFactor: (factor: number) =>
this.send(MessageType.StoreSet, 'zoomFactor', factor),
setLocalStorageValue: (key: string, value: string): Promise<void> =>
this.send(MessageType.SetLocalStorageValue, key, value),
};

readonly appMenu = {
Expand Down
42 changes: 36 additions & 6 deletions test/store.spec.ts → test/storage.spec.ts
@@ -1,6 +1,8 @@
import anyTest, { TestInterface, ExecutionContext } from 'ava';
import fs from 'fs';
import path from 'path';
import proxyquire from 'proxyquire';
import { timeout } from '../app/javascripts/main/utils';
import { createDriver, Driver } from './driver';

const { serializeStoreData } = proxyquire('../app/javascripts/main/store', {
Expand All @@ -10,7 +12,7 @@ const { serializeStoreData } = proxyquire('../app/javascripts/main/store', {
});

async function validateData(t: ExecutionContext<Driver>) {
const data = await t.context.store.dataOnDisk();
const data = await t.context.storage.dataOnDisk();

/**
* There should always be 8 values in the store.
Expand Down Expand Up @@ -41,7 +43,7 @@ async function validateData(t: ExecutionContext<Driver>) {

t.is(typeof data.backupsLocation, 'string');

t.is(typeof data.useNativeKeychain, 'boolean');
t.is(data.useNativeKeychain, null);

if (process.platform === 'darwin') {
t.is(data.selectedSpellCheckerLanguageCodes, null);
Expand All @@ -67,15 +69,15 @@ test('has valid data', async (t) => {
});

test('recreates a missing data file', async (t) => {
const location = await t.context.store.dataLocation();
const location = await t.context.storage.dataLocation();
/** Delete the store's backing file */
await fs.promises.unlink(location);
await t.context.restart();
await validateData(t);
});

test('recovers from corrupted data', async (t) => {
const location = await t.context.store.dataLocation();
const location = await t.context.storage.dataLocation();
/** Write bad data in the store's file */
await fs.promises.writeFile(location, '\uFFFF'.repeat(300));
await t.context.restart();
Expand All @@ -84,8 +86,8 @@ test('recovers from corrupted data', async (t) => {

test('persists changes to disk after setting a value', async (t) => {
const factor = 4.8;
await t.context.store.setZoomFactor(factor);
const diskData = await t.context.store.dataOnDisk();
await t.context.storage.setZoomFactor(factor);
const diskData = await t.context.storage.dataOnDisk();
t.is(diskData.zoomFactor, factor);
});

Expand All @@ -99,3 +101,31 @@ test('serializes string sets to an array', (t) => {
})
);
});

test.only('deletes local storage data after signing out', async (t) => {
function readLocalStorageContents() {
return fs.promises.readFile(
path.join(
t.context.userDataPath,
'Local Storage',
'leveldb',
'000003.log'
),
{
encoding: 'utf8',
}
);
}
await t.context.windowLoaded;
await t.context.storage.setLocalStorageValue('foo', 'bar');
let localStorageContents = await readLocalStorageContents();
t.is(localStorageContents.includes('foo'), true);
t.is(localStorageContents.includes('bar'), true);

await timeout(1_000);
await t.context.window.executeJavascript('bridge.onSignOut()');
await timeout(1_000);
localStorageContents = await readLocalStorageContents();
t.is(localStorageContents.includes('foo'), false);
t.is(localStorageContents.includes('bar'), false);
});
2 changes: 1 addition & 1 deletion web
Submodule web updated from 6c1622 to 3111dc

0 comments on commit c6d4ffd

Please sign in to comment.