diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2023-12-29 19:17:46 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-30 00:17:46 +0000 |
commit | 7303da3991814a0ce220bf2fff3e51b968913b86 (patch) | |
tree | 809c289d824ec2a08c5ff54579766b7f5c5e09e1 /ext/js/display | |
parent | 1b0e0c551d1505ed4242c04ebac224e5fff81f04 (diff) |
Cross frame API safety (#491)
* Require error type
* Add TODOs
* Fix init
* Updates
* More type safety
* Fix incorrect API map
* Update type safety
* Updates
* Add API
* Update types
* Update types
* Updates
* Remove unused
* Restore types
* Update frame ancestry handler
* Simplify names
* Fix
* Remove old message handlers
Diffstat (limited to 'ext/js/display')
-rw-r--r-- | ext/js/display/display-resizer.js | 4 | ||||
-rw-r--r-- | ext/js/display/display.js | 74 |
2 files changed, 38 insertions, 40 deletions
diff --git a/ext/js/display/display-resizer.js b/ext/js/display/display-resizer.js index 794398b8..8245e0bb 100644 --- a/ext/js/display/display-resizer.js +++ b/ext/js/display/display-resizer.js @@ -174,7 +174,7 @@ export class DisplayResizer { if (parentPopupId === null) { return; } /** @type {import('popup').ValidSize} */ - const size = await this._display.invokeParentFrame('PopupFactory.getFrameSize', {id: parentPopupId}); + const size = await this._display.invokeParentFrame('popupFactoryGetFrameSize', {id: parentPopupId}); if (this._token !== token) { return; } const {width, height} = size; this._startSize = {width, height}; @@ -210,7 +210,7 @@ export class DisplayResizer { height += y - this._startOffset.y; width = Math.max(Math.max(0, handleSize.width), width); height = Math.max(Math.max(0, handleSize.height), height); - await this._display.invokeParentFrame('PopupFactory.setFrameSize', {id: parentPopupId, width, height}); + await this._display.invokeParentFrame('popupFactorySetFrameSize', {id: parentPopupId, width, height}); } /** diff --git a/ext/js/display/display.js b/ext/js/display/display.js index e3c92ee2..cae394f8 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -19,7 +19,7 @@ import {ThemeController} from '../app/theme-controller.js'; import {FrameEndpoint} from '../comm/frame-endpoint.js'; import {DynamicProperty, EventDispatcher, EventListenerCollection, clone, deepEqual, log, promiseTimeout} from '../core.js'; -import {invokeApiMapHandler} from '../core/api-map.js'; +import {extendApiMap, invokeApiMapHandler} from '../core/api-map.js'; import {ExtensionError} from '../core/extension-error.js'; import {PopupMenu} from '../dom/popup-menu.js'; import {querySelectorNotNull} from '../dom/query-selector.js'; @@ -91,7 +91,7 @@ export class Display extends EventDispatcher { }); /** @type {import('display').DirectApiMap} */ this._directApiMap = new Map(); - /** @type {import('display').WindowApiMap} */ + /** @type {import('api-map').ApiMap<import('display').WindowApiSurface>} */ // import('display').WindowApiMap this._windowApiMap = new Map(); /** @type {DisplayHistory} */ this._history = new DisplayHistory({clearable: true, useBrowserHistory: false}); @@ -328,7 +328,8 @@ export class Display extends EventDispatcher { this._progressIndicatorVisible.on('change', this._onProgressIndicatorVisibleChanged.bind(this)); yomitan.on('extensionUnloaded', this._onExtensionUnloaded.bind(this)); yomitan.crossFrame.registerHandlers([ - ['popupMessage', this._onDirectMessage.bind(this)] + ['displayPopupMessage1', this._onDisplayPopupMessage1.bind(this)], + ['displayPopupMessage2', this._onDisplayPopupMessage2.bind(this)] ]); window.addEventListener('message', this._onWindowMessage.bind(this), false); @@ -507,25 +508,21 @@ export class Display extends EventDispatcher { * @param {import('display').DirectApiMapInit} handlers */ registerDirectMessageHandlers(handlers) { - for (const [name, handlerInfo] of handlers) { - this._directApiMap.set(name, handlerInfo); - } + extendApiMap(this._directApiMap, handlers); } /** * @param {import('display').WindowApiMapInit} handlers */ registerWindowMessageHandlers(handlers) { - for (const [name, handlerInfo] of handlers) { - this._windowApiMap.set(name, handlerInfo); - } + extendApiMap(this._windowApiMap, handlers); } /** */ close() { switch (this._pageType) { case 'popup': - this.invokeContentOrigin('Frontend.closePopup'); + this.invokeContentOrigin('frontendClosePopup', void 0); break; case 'search': this._closeTab(); @@ -578,12 +575,12 @@ export class Display extends EventDispatcher { } /** - * @template [TReturn=unknown] - * @param {string} action - * @param {import('core').SerializableObject} [params] - * @returns {Promise<TReturn>} + * @template {import('cross-frame-api').ApiNames} TName + * @param {TName} action + * @param {import('cross-frame-api').ApiParams<TName>} params + * @returns {Promise<import('cross-frame-api').ApiReturn<TName>>} */ - async invokeContentOrigin(action, params = {}) { + async invokeContentOrigin(action, params) { if (this._contentOriginTabId === this._tabId && this._contentOriginFrameId === this._frameId) { throw new Error('Content origin is same page'); } @@ -594,12 +591,12 @@ export class Display extends EventDispatcher { } /** - * @template [TReturn=unknown] - * @param {string} action - * @param {import('core').SerializableObject} [params] - * @returns {Promise<TReturn>} + * @template {import('cross-frame-api').ApiNames} TName + * @param {TName} action + * @param {import('cross-frame-api').ApiParams<TName>} params + * @returns {Promise<import('cross-frame-api').ApiReturn<TName>>} */ - async invokeParentFrame(action, params = {}) { + async invokeParentFrame(action, params) { if (this._parentFrameId === null || this._parentFrameId === this._frameId) { throw new Error('Invalid parent frame'); } @@ -634,14 +631,17 @@ export class Display extends EventDispatcher { // Message handlers - /** - * @param {import('frame-client').Message<import('display').DirectApiMessageAny>} data - * @returns {Promise<import('display').DirectApiReturnAny>} - * @throws {Error} - */ - _onDirectMessage(data) { + /** @type {import('cross-frame-api').ApiHandler<'displayPopupMessage1'>} */ + async _onDisplayPopupMessage1(message) { + /** @type {import('display').DirectApiMessageAny} */ + const messageInner = this._authenticateMessageData(message); + return await this._onDisplayPopupMessage2(messageInner); + } + + /** @type {import('cross-frame-api').ApiHandler<'displayPopupMessage2'>} */ + _onDisplayPopupMessage2(message) { return new Promise((resolve, reject) => { - const {action, params} = this._authenticateMessageData(data); + const {action, params} = message; invokeApiMapHandler( this._directApiMap, action, @@ -663,9 +663,10 @@ export class Display extends EventDispatcher { } /** - * @param {MessageEvent<import('frame-client').Message<import('display').WindowApiMessageAny>>} details + * @param {MessageEvent<import('display').WindowApiFrameClientMessageAny>} details */ _onWindowMessage({data}) { + /** @type {import('display').WindowApiMessageAny} */ let data2; try { data2 = this._authenticateMessageData(data); @@ -676,7 +677,7 @@ export class Display extends EventDispatcher { try { const {action, params} = data2; const callback = () => {}; // NOP - invokeApiMapHandler(this._directApiMap, action, params, [], callback); + invokeApiMapHandler(this._windowApiMap, action, params, [], callback); } catch (e) { // NOP } @@ -729,18 +730,15 @@ export class Display extends EventDispatcher { /** * @template [T=unknown] - * @param {T|import('frame-client').Message<T>} data + * @param {import('frame-client').Message<unknown>} message * @returns {T} * @throws {Error} */ - _authenticateMessageData(data) { - if (this._frameEndpoint === null) { - return /** @type {T} */ (data); - } - if (!this._frameEndpoint.authenticate(data)) { + _authenticateMessageData(message) { + if (this._frameEndpoint !== null && !this._frameEndpoint.authenticate(message)) { throw new Error('Invalid authentication'); } - return /** @type {import('frame-client').Message<T>} */ (data).data; + return /** @type {import('frame-client').Message<T>} */ (message).data; } /** */ @@ -1767,7 +1765,7 @@ export class Display extends EventDispatcher { /** @type {string} */ let text; try { - text = await this.invokeContentOrigin('Frontend.getSelectionText'); + text = await this.invokeContentOrigin('frontendGetSelectionText', void 0); } catch (e) { break; } @@ -1775,7 +1773,7 @@ export class Display extends EventDispatcher { } break; default: - await this.invokeContentOrigin('Frontend.copySelection'); + await this.invokeContentOrigin('frontendCopySelection', void 0); break; } } |