this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove legacy session-in/out WASM exports

Four wasm-bindgen free functions survived the migration to the
OpakeContext path and kept shipping in dist/ even though every TS
caller goes through the context methods now:

- proactiveSessionRefresh → opake.proactiveRefresh()
- cleanupExpiredPairRequests → opake.cleanupExpiredPairRequests()
- healStaleGrants → opake.healStaleGrants()
- retryPendingShares → opake.retryPendingSharesViaOpake()

Each took `session_js: JsValue` and threaded the session back through
`result_with_session` — the pre-OpakeContext shape that violated the
WASM security boundary (tokens + DPoP keys serialized into JS memory).
The replacement context methods keep all session material inside WASM
and were already documented as canonical. A contributor who grepped
for e.g. `healStaleGrants` and saw both shapes had no way to tell
which was correct; this deletes the decoy.

Rust-internal helpers that only the legacy path used are deleted too:

- wasm_util::make_client
- wasm_util::result_with_session
- wasm_util::priv_key_from_slice

`pub_key_from_slice` stays (used by the current OpakeContext and
FileManager bindings). The daemon module keeps its constants exports
and `daemonTaskDefs` — those are what the Service Worker and CLI
share agreement on.

+12 -199
+10 -140
crates/opake-wasm/src/daemon.rs
··· 1 - // WASM exports for Service Worker maintenance tasks: 2 - // session refresh, pair request cleanup, stale grant healing. 1 + // WASM exports for the daemon task registry + related constants. 2 + // 3 + // Maintenance operations themselves (session refresh, pair-request 4 + // cleanup, stale-grant healing, pending-share retry) live on 5 + // `OpakeContext` — the SDK calls `opake.cleanupExpiredPairRequests()`, 6 + // `opake.healStaleGrants()`, `opake.retryPendingShares()`, and 7 + // `opake.proactiveRefresh()` directly. This module is intentionally 8 + // narrow: constants that the Service Worker and the CLI need to agree 9 + // on, and the task registry the daemon reads. 3 10 4 - use opake_core::client::session_refresh::{ 5 - proactive_refresh, RefreshOutcome, DEFAULT_REFRESH_THRESHOLD_SECONDS, 6 - }; 7 - use opake_core::client::{time, Session, WasmTransport}; 8 - use opake_core::crypto::OsRng; 11 + use opake_core::indexer::daemon; 9 12 use opake_core::pairing::DEFAULT_PAIR_REQUEST_TTL_SECONDS; 10 - use serde::Serialize; 11 13 use wasm_bindgen::prelude::*; 12 - 13 - use opake_core::indexer::daemon; 14 - 15 - use crate::wasm_util; 16 - 17 - // --------------------------------------------------------------------------- 18 - // Constants (exported so the Service Worker uses the same values as the CLI) 19 - // --------------------------------------------------------------------------- 20 14 21 15 /// Returns the daemon task registry as a JSON array: 22 16 /// `[{ name, intervalSeconds, description }, ...]` ··· 55 49 pub fn default_pending_share_ttl_seconds() -> f64 { 56 50 opake_core::sharing::DEFAULT_PENDING_SHARE_TTL_SECONDS as f64 57 51 } 58 - 59 - // --------------------------------------------------------------------------- 60 - // Session refresh 61 - // --------------------------------------------------------------------------- 62 - 63 - /// Check whether a session needs refreshing and, if so, refresh it. 64 - /// 65 - /// Returns the updated session as a JS object, or `null` if no refresh was 66 - /// needed. Throws on failure. 67 - #[wasm_bindgen(js_name = proactiveSessionRefresh)] 68 - pub async fn proactive_session_refresh( 69 - session_js: JsValue, 70 - pds_url: &str, 71 - threshold_seconds: f64, 72 - ) -> Result<JsValue, JsError> { 73 - let session: Session = 74 - serde_wasm_bindgen::from_value(session_js).map_err(|e| JsError::new(&e.to_string()))?; 75 - let transport = WasmTransport::new(); 76 - let now = time::unix_now(); 77 - 78 - let result = proactive_refresh( 79 - &transport, 80 - &session, 81 - pds_url, 82 - threshold_seconds as i64, 83 - now, 84 - &mut OsRng, 85 - ) 86 - .await; 87 - 88 - match result { 89 - RefreshOutcome::Refreshed(new_session) => { 90 - let serializer = serde_wasm_bindgen::Serializer::new().serialize_maps_as_objects(true); 91 - new_session 92 - .serialize(&serializer) 93 - .map_err(|e| JsError::new(&e.to_string())) 94 - } 95 - RefreshOutcome::NotNeeded => Ok(JsValue::NULL), 96 - RefreshOutcome::Failed(e) => Err(JsError::new(&e.to_string())), 97 - } 98 - } 99 - 100 - // --------------------------------------------------------------------------- 101 - // Pair request cleanup 102 - // --------------------------------------------------------------------------- 103 - 104 - /// Delete expired pair requests and orphaned pair responses. 105 - /// 106 - /// Returns `{ result: { requestsDeleted, responsesDeleted }, session }`. 107 - /// The caller must persist the returned session (DPoP nonce or token may 108 - /// have been updated during the XRPC calls). 109 - #[wasm_bindgen(js_name = cleanupExpiredPairRequests)] 110 - pub async fn cleanup_expired_pair_requests_js( 111 - session_js: JsValue, 112 - pds_url: &str, 113 - ttl_seconds: f64, 114 - ) -> Result<JsValue, JsError> { 115 - let mut client = wasm_util::make_client(pds_url, session_js)?; 116 - let now = time::unix_now(); 117 - 118 - let result = 119 - opake_core::pairing::cleanup_expired_pair_requests(&mut client, now, ttl_seconds as i64) 120 - .await 121 - .map_err(|e| JsError::new(&e.to_string()))?; 122 - 123 - wasm_util::result_with_session(&client, &result) 124 - } 125 - 126 - // --------------------------------------------------------------------------- 127 - // Stale grant healing 128 - // --------------------------------------------------------------------------- 129 - 130 - /// Check all grants and delete any whose recipient has no valid public key. 131 - /// 132 - /// Returns `{ result: { grantsChecked, grantsDeleted, grantsFailed }, session }`. 133 - /// The caller must persist the returned session. 134 - #[wasm_bindgen(js_name = healStaleGrants)] 135 - pub async fn heal_stale_grants_js(session_js: JsValue, pds_url: &str) -> Result<JsValue, JsError> { 136 - let mut client = wasm_util::make_client(pds_url, session_js)?; 137 - 138 - let result = opake_core::sharing::heal_stale_grants(&mut client) 139 - .await 140 - .map_err(|e| JsError::new(&e.to_string()))?; 141 - 142 - wasm_util::result_with_session(&client, &result) 143 - } 144 - 145 - // --------------------------------------------------------------------------- 146 - // Pending share retry 147 - // --------------------------------------------------------------------------- 148 - 149 - /// Retry all pending shares for the authenticated account. 150 - /// 151 - /// Returns `{ result: { checked, completed, expired, stillPending, failed }, session }`. 152 - /// The caller must persist the returned session. 153 - #[wasm_bindgen(js_name = retryPendingShares)] 154 - pub async fn retry_pending_shares_js( 155 - session_js: JsValue, 156 - pds_url: &str, 157 - owner_did: &str, 158 - private_key: &[u8], 159 - ttl_seconds: f64, 160 - ) -> Result<JsValue, JsError> { 161 - use opake_core::sharing::{retry_pending_shares, RetryParams}; 162 - 163 - let privkey = wasm_util::priv_key_from_slice(private_key)?; 164 - let mut client = wasm_util::make_client(pds_url, session_js)?; 165 - let transport = opake_core::client::WasmTransport::new(); 166 - let now = time::unix_now(); 167 - 168 - let params = RetryParams { 169 - caller_pds_url: pds_url, 170 - owner_did, 171 - owner_private_key: &privkey, 172 - now, 173 - ttl_seconds: ttl_seconds as i64, 174 - }; 175 - 176 - let result = retry_pending_shares(&mut client, &transport, &params, &mut OsRng) 177 - .await 178 - .map_err(|e| JsError::new(&e.to_string()))?; 179 - 180 - wasm_util::result_with_session(&client, &result) 181 - }
+2 -59
crates/opake-wasm/src/wasm_util.rs
··· 1 1 // Shared helpers for WASM exports that bridge opake-core ↔ JS. 2 2 3 - use opake_core::client::{Session, WasmTransport, XrpcClient}; 4 - use opake_core::crypto::{X25519PrivateKey, X25519PublicKey}; 3 + use opake_core::client::WasmTransport; 4 + use opake_core::crypto::X25519PublicKey; 5 5 use serde::Serialize; 6 6 use wasm_bindgen::prelude::*; 7 7 8 - /// Create a short-lived XrpcClient from a JS session object. 9 - /// 10 - /// Session's custom Deserialize impl uses serde's native tagged enum support 11 - /// with an untagged fallback for backward compat. This works correctly with 12 - /// serde_wasm_bindgen (no intermediate serde_json::Value conversion). 13 - pub fn make_client( 14 - pds_url: &str, 15 - session_json: JsValue, 16 - ) -> Result<XrpcClient<WasmTransport>, JsError> { 17 - let session: Session = 18 - serde_wasm_bindgen::from_value(session_json).map_err(|e| JsError::new(&e.to_string()))?; 19 - Ok(XrpcClient::with_session( 20 - WasmTransport::new(), 21 - pds_url.to_string(), 22 - session, 23 - )) 24 - } 25 - 26 - /// Serialize an operation result alongside the (potentially updated) session. 27 - /// 28 - /// Every WASM export that touches the PDS returns the session because DPoP 29 - /// nonce captures and token refreshes mutate it. The JS caller persists the 30 - /// updated session after each call. 31 - pub fn result_with_session<T: Serialize>( 32 - client: &XrpcClient<WasmTransport>, 33 - payload: &T, 34 - ) -> Result<JsValue, JsError> { 35 - #[derive(Serialize)] 36 - struct WasmResult<'a, T: Serialize> { 37 - result: &'a T, 38 - session: Session, 39 - } 40 - 41 - let session = client 42 - .session() 43 - .cloned() 44 - .ok_or_else(|| JsError::new("session lost"))?; 45 - let result = WasmResult { 46 - result: payload, 47 - session, 48 - }; 49 - // serialize_maps_as_objects: serde_json::Value::Object → plain JS object (not Map). 50 - // Without this, nested JSON values (e.g. RecordEntry.value) become Maps, and 51 - // field access returns Map.prototype methods instead of record fields. 52 - let serializer = serde_wasm_bindgen::Serializer::new().serialize_maps_as_objects(true); 53 - result 54 - .serialize(&serializer) 55 - .map_err(|e| JsError::new(&e.to_string())) 56 - } 57 - 58 8 /// Convert an opake-core Error into a structured JsError. 59 9 /// 60 10 /// Format: `"Kind: message"` — the TS SDK parses this prefix to produce ··· 86 36 bytes 87 37 .try_into() 88 38 .map_err(|_| JsError::new("public key must be 32 bytes")) 89 - } 90 - 91 - /// Parse a 32-byte private key from a JS Uint8Array slice. 92 - pub fn priv_key_from_slice(bytes: &[u8]) -> Result<X25519PrivateKey, JsError> { 93 - bytes 94 - .try_into() 95 - .map_err(|_| JsError::new("private key must be 32 bytes")) 96 39 } 97 40 98 41 use opake_core::crypto::OsRng;