123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // 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<object>} 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<object>} 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<any>} 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()
- })()
|