// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT /** * IMPORTANT: See ipc.js for the main frame implementation. * main frame -> isolation frame = isolation payload * isolation frame -> main frame = isolation message */ ;(async function () { /** * Sends the message to the isolation frame. * @param {any} message */ function sendMessage(message) { window.parent.postMessage(message, '*') } /** * @type {Uint8Array} - Injected by Tauri during runtime */ const aesGcmKeyRaw = new Uint8Array(__TEMPLATE_runtime_aes_gcm_key__) /** * @type {CryptoKey} */ const aesGcmKey = await window.crypto.subtle.importKey( 'raw', aesGcmKeyRaw, 'AES-GCM', false, ['encrypt'] ) /** * @param {object} data * @return {Promise<{nonce: number[], payload: number[]}>} */ async function encrypt(data) { const algorithm = Object.create(null) algorithm.name = 'AES-GCM' algorithm.iv = window.crypto.getRandomValues(new Uint8Array(12)) const encoder = new TextEncoder() const encoded = encoder.encode(__RAW_process_ipc_message_fn__(data).data) return window.crypto.subtle .encrypt(algorithm, aesGcmKey, encoded) .then((payload) => { const result = Object.create(null) result.nonce = Array.from(new Uint8Array(algorithm.iv)) result.payload = Array.from(new Uint8Array(payload)) return result }) } /** * Detects if a message event is a valid isolation message. * * @param {MessageEvent} event - a message event that is expected to be an isolation message * @return {boolean} - if the event was a valid isolation message */ function isIsolationMessage(data) { if (typeof data === 'object' && typeof data.payload === 'object') { const keys = data.payload ? Object.keys(data.payload) : [] return ( keys.length > 0 && keys.every((key) => key === 'nonce' || key === 'payload') ) } return false } /** * Detect if a message event is a valid isolation payload. * * @param {MessageEvent} event - a message event that is expected to be an isolation payload * @return boolean */ function isIsolationPayload(data) { return ( typeof data === 'object' && 'callback' in data && 'error' in data && !isIsolationMessage(data) ) } /** * Handle incoming payload events. * @param {MessageEvent} event */ async function payloadHandler(event) { if (!isIsolationPayload(event.data)) { return } let data = event.data if (typeof window.__TAURI_ISOLATION_HOOK__ === 'function') { // await even if it's not async so that we can support async ones data = await window.__TAURI_ISOLATION_HOOK__(data) } const message = Object.create(null) message.cmd = data.cmd message.callback = data.callback message.error = data.error message.options = data.options message.payload = await encrypt(data.payload) sendMessage(message) } window.addEventListener('message', payloadHandler, false) /** * @type {number} - How many milliseconds to wait between ready checks */ const readyIntervalMs = 50 /** * Wait until this Isolation context is ready to receive messages, and let the main frame know. */ function waitUntilReady() { // consider either a function or an explicitly set null value as the ready signal if ( typeof window.__TAURI_ISOLATION_HOOK__ === 'function' || window.__TAURI_ISOLATION_HOOK__ === null ) { sendMessage('__TAURI_ISOLATION_READY__') } else { setTimeout(waitUntilReady, readyIntervalMs) } } setTimeout(waitUntilReady, readyIntervalMs) document.currentScript.remove() })()