#![allow(missing_docs)]
use thiserror::Error;
use wasm_bindgen::{prelude::*, JsCast, JsValue};
use web_sys::{Crypto, SubtleCrypto, Window, WorkerGlobalScope};
pub enum WindowOrWorker {
Window(Window),
Worker(WorkerGlobalScope),
}
impl WindowOrWorker {
pub fn new() -> Result<Self, WasmCryptoError> {
#[wasm_bindgen]
extern "C" {
type Global;
#[wasm_bindgen(method, getter, js_name = Window)]
fn window(this: &Global) -> JsValue;
#[wasm_bindgen(method, getter, js_name = WorkerGlobalScope)]
fn worker(this: &Global) -> JsValue;
}
let global: Global = js_sys::global().unchecked_into();
if !global.window().is_undefined() {
Ok(Self::Window(global.unchecked_into()))
} else if !global.worker().is_undefined() {
Ok(Self::Worker(global.unchecked_into()))
} else {
Err(WasmCryptoError::UnknownContext)
}
}
pub fn crypto(&self) -> Result<Crypto, WasmCryptoError> {
match self {
Self::Window(window) => window.crypto(),
Self::Worker(worker) => worker.crypto(),
}
.map_err(|_err| WasmCryptoError::NoCryptoAvailable)
}
pub fn subtle_crypto(&self) -> Result<SubtleCrypto, WasmCryptoError> {
Ok(self.crypto()?.subtle())
}
}
#[derive(Debug, Error, Eq, PartialEq)]
pub enum WasmCryptoError {
#[error("could not find window or worker in global environment")]
UnknownContext,
#[error("window or worker's .crypto() method failed")]
NoCryptoAvailable,
}