(core) Fix problem with localStorage in some cross-origin embed situations

Summary:
- Handle the possibility that any access to localStorage causes error.
- Move getStorage() and getSessionStorage() safe functions to a separate file.
- Use these safe functions in more places.

Test Plan:
Added a test case, using a webdriver instance that blocks third-party cookies,
to enforce third-party restrictions. Added to gristUtil a way to override the
webdriver instance.

Reviewers: jarek

Reviewed By: jarek

Differential Revision: https://phab.getgrist.com/D3719
This commit is contained in:
Dmitry S
2022-11-30 10:55:47 -05:00
parent 59942a23b6
commit 29a7eadb85
8 changed files with 93 additions and 75 deletions

View File

@@ -1,6 +1,6 @@
import {CursorPos} from 'app/client/components/Cursor';
import {GristDoc} from 'app/client/components/GristDoc';
import {getStorage} from 'app/client/lib/localStorageObs';
import {getStorage} from 'app/client/lib/storage';
import {IDocPage, isViewDocPage, ViewDocPage} from 'app/common/gristUrls';
import {Disposable, Listener, Observable} from 'grainjs';
import {reportError} from 'app/client/models/errors';

View File

@@ -1,7 +1,7 @@
import {CellPosition, toCursor} from 'app/client/components/CellPosition';
import {oneTimeListener} from 'app/client/components/CursorMonitor';
import {GristDoc} from 'app/client/components/GristDoc';
import {getStorage} from 'app/client/lib/localStorageObs';
import {getStorage} from 'app/client/lib/storage';
import {UserError} from 'app/client/models/errors';
import {FieldEditor, FieldEditorStateEvent} from 'app/client/widgets/FieldEditor';
import {isViewDocPage} from 'app/common/gristUrls';

View File

@@ -1,5 +1,6 @@
import {get as getBrowserGlobals} from 'app/client/lib/browserGlobals';
import {guessTimezone} from 'app/client/lib/guessTimezone';
import {getSessionStorage} from 'app/client/lib/storage';
import {getWorker} from 'app/client/models/gristConfigCache';
import {CommResponseBase} from 'app/common/CommTypes';
import * as gutil from 'app/common/gutil';
@@ -70,6 +71,8 @@ export interface GristWSSettings {
* An implementation of Grist websocket connection settings for the browser.
*/
export class GristWSSettingsBrowser implements GristWSSettings {
private _sessionStorage = getSessionStorage();
public makeWebSocket(url: string) { return new WebSocket(url); }
public getTimezone() { return guessTimezone(); }
public getPageUrl() { return G.window.location.href; }
@@ -77,18 +80,18 @@ export class GristWSSettingsBrowser implements GristWSSettings {
return getDocWorkerUrl(assignmentId);
}
public getClientId(assignmentId: string|null) {
return window.sessionStorage.getItem(`clientId_${assignmentId}`) || null;
return this._sessionStorage.getItem(`clientId_${assignmentId}`) || null;
}
public getUserSelector(): string {
// TODO: find/create a more official way to get the user.
return (window as any).gristDocPageModel?.appModel.currentUser?.email || '';
}
public updateClientId(assignmentId: string|null, id: string) {
window.sessionStorage.setItem(`clientId_${assignmentId}`, id);
this._sessionStorage.setItem(`clientId_${assignmentId}`, id);
}
public advanceCounter(): string {
const value = parseInt(window.sessionStorage.getItem('clientCounter')!, 10) || 0;
window.sessionStorage.setItem('clientCounter', String(value + 1));
const value = parseInt(this._sessionStorage.getItem('clientCounter')!, 10) || 0;
this._sessionStorage.setItem('clientCounter', String(value + 1));
return String(value);
}
public log(...args: any[]): void {