mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
155 lines
4.2 KiB
JavaScript
155 lines
4.2 KiB
JavaScript
// 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 {string} - The main frame origin.
|
|
*/
|
|
const origin = __TEMPLATE_origin__
|
|
|
|
/**
|
|
* @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(payload) {
|
|
const algorithm = Object.create(null)
|
|
algorithm.name = 'AES-GCM'
|
|
algorithm.iv = window.crypto.getRandomValues(new Uint8Array(12))
|
|
|
|
const { contentType, data } = __RAW_process_ipc_message_fn__(payload)
|
|
|
|
const message =
|
|
typeof data === 'string'
|
|
? new TextEncoder().encode(data)
|
|
: ArrayBuffer.isView(data) || data instanceof ArrayBuffer
|
|
? data
|
|
: new Uint8Array(data)
|
|
|
|
return window.crypto.subtle
|
|
.encrypt(algorithm, aesGcmKey, message)
|
|
.then((payload) => {
|
|
const result = Object.create(null)
|
|
result.nonce = Array.from(new Uint8Array(algorithm.iv))
|
|
result.payload = Array.from(new Uint8Array(payload))
|
|
result.contentType = contentType
|
|
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' || key === 'contentType'
|
|
)
|
|
)
|
|
}
|
|
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 (event.origin !== origin || !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()
|