Skip to main content

lib_q_core/wasm/
error.rs

1//! WASM Error Handling Module
2//!
3//! This module provides secure, consistent error handling for WASM bindings.
4//! It ensures all WASM functions return Result<T, JsValue> consistently and
5//! provides secure error conversion without information leakage.
6
7#[cfg(feature = "wasm")]
8use wasm_bindgen::prelude::*;
9
10use crate::error::Error;
11
12/// Convert Error to JsValue for WASM compatibility
13///
14/// This function provides secure error conversion that:
15/// - Prevents information leakage through error messages
16/// - Ensures consistent error handling across WASM bindings
17/// - Maintains security by not exposing internal implementation details
18#[cfg(feature = "wasm")]
19pub fn error_to_js_value(error: Error) -> JsValue {
20    // Security: Use generic error messages to prevent information leakage
21    let message = match error {
22        Error::InvalidAlgorithm { .. } => "Invalid algorithm specified",
23        Error::InvalidKeySize { .. } => "Invalid key size",
24        Error::InvalidMessageSize { .. } => "Invalid message size",
25        Error::InvalidNonceSize { .. } => "Invalid nonce size",
26        Error::InvalidSignatureSize { .. } => "Invalid signature",
27        Error::InvalidCiphertextSize { .. } => "Invalid ciphertext",
28        Error::InvalidPlaintextSize { .. } => "Invalid plaintext",
29        Error::InvalidKeyFormat => "Invalid key material",
30        Error::InvalidSecurityLevel { .. } => "Invalid security level",
31        Error::NotImplemented { .. } => "Feature not implemented",
32        Error::ProviderNotConfigured { .. } => "Provider not configured",
33        Error::VerificationFailed { .. } => "Verification failed",
34        Error::EncryptionFailed { .. } => "Encryption failed",
35        Error::DecryptionFailed { .. } => "Decryption failed",
36        Error::KeyGenerationFailed { .. } => "Key generation failed",
37        Error::RandomGenerationFailed { .. } => "Random generation failed",
38        Error::SigningFailed { .. } => "Signing failed",
39        Error::MemoryAllocationFailed { .. } => "Memory allocation failed",
40        Error::InternalError { .. } => "Internal error",
41        Error::UnsupportedOperation { .. } => "Unsupported operation",
42        Error::InvalidState { .. } => "Invalid context state",
43        Error::PluginDependencyError { .. } => "Plugin dependency error",
44        Error::PluginVersionIncompatible { .. } => "Plugin version incompatible",
45        Error::InvalidKey { .. } => "Invalid key",
46        Error::UnsupportedAlgorithm { .. } => "Unsupported algorithm",
47        Error::AuthenticationFailed { .. } => "Authentication failed",
48        Error::InvalidAssociatedDataSize { .. } => "Invalid associated data size",
49        Error::InvalidTagSize { .. } => "Invalid tag size",
50        Error::InvalidHashSize { .. } => "Invalid hash size",
51        Error::InvalidRandomnessSize { .. } => "Invalid randomness size",
52        Error::RandomBytesLengthInvalid { .. } => "Invalid random length",
53        Error::HexDecode(..) => "Invalid hex encoding",
54        Error::BufferTooSmall { .. } => "Insufficient buffer capacity",
55    };
56
57    JsValue::from_str(message)
58}
59
60/// Helper function to convert Result<T, Error> to Result<T, JsValue>
61///
62/// This function provides a secure conversion that:
63/// - Maintains type safety
64/// - Ensures consistent error handling
65/// - Prevents information leakage
66#[cfg(feature = "wasm")]
67pub fn convert_result<T>(result: Result<T, Error>) -> Result<T, JsValue> {
68    result.map_err(error_to_js_value)
69}
70
71/// WASM-safe algorithm parsing that returns JsValue errors
72///
73/// This function provides secure algorithm parsing that:
74/// - Validates input strings
75/// - Returns consistent error types
76/// - Prevents injection attacks
77#[cfg(feature = "wasm")]
78pub fn parse_algorithm_wasm(algorithm: &str) -> Result<crate::api::Algorithm, JsValue> {
79    // Security: Validate input length to prevent DoS attacks
80    if algorithm.len() > 64 {
81        return Err(JsValue::from_str("Algorithm name too long"));
82    }
83
84    // Reject control characters; allow Unicode for algorithm string forms that use non-ASCII.
85    // [`crate::wasm::conversions::WasmConversions::string_to_algorithm`].
86    if algorithm.chars().any(|c| c.is_control()) {
87        return Err(JsValue::from_str("Invalid algorithm name format"));
88    }
89
90    match crate::wasm::conversions::WasmConversions::string_to_algorithm(algorithm) {
91        Ok(a) => Ok(a),
92        Err(Error::UnsupportedAlgorithm { .. }) => Err(JsValue::from_str("Unsupported algorithm")),
93        Err(_) => Err(JsValue::from_str("Invalid algorithm specified")),
94    }
95}
96
97/// Secure WASM error handling macro
98///
99/// This macro provides secure error handling for WASM functions that:
100/// - Ensures consistent error types
101/// - Prevents information leakage
102/// - Maintains security boundaries
103#[cfg(feature = "wasm")]
104#[macro_export]
105macro_rules! wasm_result {
106    ($expr:expr) => {
107        match $expr {
108            Ok(value) => Ok(value),
109            Err(error) => Err($crate::wasm::error::error_to_js_value(error)),
110        }
111    };
112}
113
114/// Secure WASM validation macro
115///
116/// This macro provides secure validation for WASM inputs that:
117/// - Validates input parameters
118/// - Returns consistent error types
119/// - Prevents injection attacks
120#[cfg(feature = "wasm")]
121#[macro_export]
122macro_rules! wasm_validate {
123    ($condition:expr, $error_msg:expr) => {
124        if !$condition {
125            return Err(JsValue::from_str($error_msg));
126        }
127    };
128}
129
130/// Secure WASM serialization helper
131///
132/// This function provides secure serialization that:
133/// - Handles serialization errors gracefully
134/// - Returns consistent error types
135/// - Prevents information leakage
136#[cfg(feature = "wasm")]
137pub fn secure_serialize<T: serde::Serialize>(value: &T) -> Result<JsValue, JsValue> {
138    match serde_wasm_bindgen::to_value(value) {
139        Ok(js_value) => Ok(js_value),
140        Err(_) => Err(JsValue::from_str("Serialization error")),
141    }
142}
143
144/// Secure WASM deserialization helper
145///
146/// This function provides secure deserialization that:
147/// - Handles deserialization errors gracefully
148/// - Returns consistent error types
149/// - Prevents information leakage
150#[cfg(feature = "wasm")]
151pub fn secure_deserialize<T: serde::de::DeserializeOwned>(value: &JsValue) -> Result<T, JsValue> {
152    match serde_wasm_bindgen::from_value(value.clone()) {
153        Ok(deserialized) => Ok(deserialized),
154        Err(_) => Err(JsValue::from_str("Deserialization error")),
155    }
156}
157
158// NOTE: these functions build a `wasm_bindgen::JsValue`, which (per prior audit finding) ABORTS
159// the process natively — observed STATUS_STACK_BUFFER_OVERRUN — outside a real wasm32 runtime.
160// They previously had `#[test]` (not `#[wasm_bindgen_test]`) fns gated on
161// `cfg(target_arch = "wasm32")`: under `cargo test` on a native host that cfg is always false, so
162// the functions compiled but the harness reported "0 tests run" — a suite that looks green while
163// exercising nothing. There is no native-safe way to test them (constructing a `JsValue` is the
164// abort trigger), so the real tests now live in `tests/wasm_smoke.rs` as `#[wasm_bindgen_test]`,
165// run only under `wasm-pack test --node` on the `wasm32-unknown-unknown` target where a JS engine
166// actually backs `JsValue`. See that file for the executed assertions.