diff options
Diffstat (limited to 'ext/js/comm/frame-endpoint.js')
-rw-r--r-- | ext/js/comm/frame-endpoint.js | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/ext/js/comm/frame-endpoint.js b/ext/js/comm/frame-endpoint.js index 5555e60f..c338e143 100644 --- a/ext/js/comm/frame-endpoint.js +++ b/ext/js/comm/frame-endpoint.js @@ -16,50 +16,73 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import {EventListenerCollection, generateId, isObject} from '../core.js'; +import {EventListenerCollection, generateId} from '../core.js'; import {yomitan} from '../yomitan.js'; export class FrameEndpoint { constructor() { + /** @type {string} */ this._secret = generateId(16); + /** @type {?string} */ this._token = null; + /** @type {EventListenerCollection} */ this._eventListeners = new EventListenerCollection(); + /** @type {boolean} */ this._eventListenersSetup = false; } + /** + * @returns {void} + */ signal() { if (!this._eventListenersSetup) { this._eventListeners.addEventListener(window, 'message', this._onMessage.bind(this), false); this._eventListenersSetup = true; } - yomitan.api.broadcastTab('frameEndpointReady', {secret: this._secret}); + /** @type {import('frame-client').FrameEndpointReadyDetails} */ + const details = {secret: this._secret}; + yomitan.api.broadcastTab('frameEndpointReady', details); } + /** + * @param {unknown} message + * @returns {boolean} + */ authenticate(message) { return ( this._token !== null && - isObject(message) && - this._token === message.token && - this._secret === message.secret + typeof message === 'object' && message !== null && + this._token === /** @type {import('core').SerializableObject} */ (message).token && + this._secret === /** @type {import('core').SerializableObject} */ (message).secret ); } - _onMessage(e) { + /** + * @param {MessageEvent<unknown>} event + */ + _onMessage(event) { if (this._token !== null) { return; } // Already initialized - const data = e.data; - if (!isObject(data) || data.action !== 'frameEndpointConnect') { return; } // Invalid message + const {data} = event; + if (typeof data !== 'object' || data === null) { return; } // Invalid message - const params = data.params; - if (!isObject(params)) { return; } // Invalid data + const {action} = /** @type {import('core').SerializableObject} */ (data); + if (action !== 'frameEndpointConnect') { return; } // Invalid message - const secret = params.secret; + const {params} = /** @type {import('core').SerializableObject} */ (data); + if (typeof params !== 'object' || params === null) { return; } // Invalid data + + const {secret} = /** @type {import('core').SerializableObject} */ (params); if (secret !== this._secret) { return; } // Invalid authentication - const {token, hostFrameId} = params; + const {token, hostFrameId} = /** @type {import('core').SerializableObject} */ (params); + if (typeof token !== 'string' || typeof hostFrameId !== 'number') { return; } // Invalid target + this._token = token; this._eventListeners.removeAllEventListeners(); - yomitan.api.sendMessageToFrame(hostFrameId, 'frameEndpointConnected', {secret, token}); + /** @type {import('frame-client').FrameEndpointConnectedDetails} */ + const details = {secret, token}; + yomitan.api.sendMessageToFrame(hostFrameId, 'frameEndpointConnected', details); } } |