wallet_standard_browser/features/experimental/
encrypt.rs

1#![allow(unsafe_code)]
2
3use async_trait::async_trait;
4use js_sys::Array;
5use serde::Deserialize;
6use serde::Serialize;
7use typed_builder::TypedBuilder;
8use wallet_standard::EXPERIMENTAL_ENCRYPT;
9use wallet_standard::ExperimentalEncryptOutput;
10use wallet_standard::ExperimentalEncryptProps;
11use wallet_standard::WalletError;
12use wallet_standard::WalletExperimentalEncrypt;
13use wallet_standard::WalletResult;
14use wasm_bindgen::JsCast;
15use wasm_bindgen::JsValue;
16use wasm_bindgen::prelude::*;
17
18use crate::BrowserWallet;
19use crate::BrowserWalletAccountInfo;
20use crate::impl_feature_from_js;
21
22impl ExperimentalEncryptOutput for BrowserExperimentalEncryptOutput {
23	fn cipher_text(&self) -> Vec<u8> {
24		self._cipher_text()
25	}
26
27	fn nonce(&self) -> Vec<u8> {
28		self._nonce()
29	}
30}
31
32#[wasm_bindgen]
33extern "C" {
34	#[derive(Clone, Debug)]
35	pub type BrowserExperimentalEncryptOutput;
36	/// `ciphertext` that was encrypted.
37	#[wasm_bindgen(method, getter, js_name = "cipher_text")]
38	pub fn _cipher_text(this: &BrowserExperimentalEncryptOutput) -> Vec<u8>;
39	/// Nonce that was used for encryption.
40	#[wasm_bindgen(method, getter, js_name = "nonce")]
41	pub fn _nonce(this: &BrowserExperimentalEncryptOutput) -> Vec<u8>;
42	#[derive(Clone, Debug)]
43	pub type ExperimentalEncryptFeature;
44	/// Version of the feature API.
45	#[wasm_bindgen(method, getter)]
46	pub fn version(this: &ExperimentalEncryptFeature) -> String;
47	/// List of ciphers supported for encryption.
48	#[wasm_bindgen(method, getter)]
49	pub fn ciphers(this: &ExperimentalEncryptFeature) -> Vec<String>;
50	/// Encrypt cleartexts using the account's secret key.
51	///
52	/// @param inputs Inputs for encryption.
53	///
54	/// @return Outputs of encryption.
55	#[allow(unused_qualifications)]
56	#[wasm_bindgen(method, variadic, catch)]
57	pub async fn encrypt(
58		this: &ExperimentalEncryptFeature,
59		args: Array,
60	) -> Result<JsValue, JsValue>;
61}
62
63impl_feature_from_js!(ExperimentalEncryptFeature, EXPERIMENTAL_ENCRYPT);
64
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, TypedBuilder)]
66#[serde(rename_all = "camelCase")]
67pub struct ExperimentalEncryptInput {
68	/// Account to use.
69	#[serde(with = "serde_wasm_bindgen::preserve")]
70	pub account: BrowserWalletAccountInfo,
71	#[serde(flatten)]
72	pub props: ExperimentalEncryptProps,
73}
74
75#[async_trait(?Send)]
76impl WalletExperimentalEncrypt for BrowserWallet {
77	type Output = BrowserExperimentalEncryptOutput;
78
79	async fn encrypt_many(
80		&self,
81		props: Vec<ExperimentalEncryptProps>,
82	) -> WalletResult<Vec<Self::Output>> {
83		let Some(ref wallet_account) = self.wallet_account else {
84			return Err(WalletError::WalletAccount);
85		};
86
87		let input = props
88			.into_iter()
89			.map(|p| {
90				ExperimentalEncryptInput::builder()
91					.account(wallet_account.clone())
92					.props(p)
93					.build()
94			})
95			.collect::<Vec<_>>();
96
97		let feature = self.wallet.get_feature::<ExperimentalEncryptFeature>()?;
98		let inputs: Array = serde_wasm_bindgen::to_value(&input)?.unchecked_into();
99		let result: Array = feature.encrypt(inputs).await?.unchecked_into();
100
101		Ok(result
102			.into_iter()
103			.map(wasm_bindgen::JsCast::unchecked_into)
104			.collect())
105	}
106
107	async fn encrypt(&self, props: ExperimentalEncryptProps) -> WalletResult<Self::Output> {
108		self.encrypt_many(vec![props])
109			.await?
110			.first()
111			.cloned()
112			.ok_or(WalletError::WalletEncrypt)
113	}
114}