diff --git a/bindings_node/CHANGELOG.md b/bindings_node/CHANGELOG.md index 426caf777..abbea749a 100644 --- a/bindings_node/CHANGELOG.md +++ b/bindings_node/CHANGELOG.md @@ -1,5 +1,9 @@ # @xmtp/node-bindings +## 0.0.22 + +- Moved `verify_signed_with_public_key` out of `Client` + ## 0.0.21 - Added `installation_id_bytes` to `Client` diff --git a/bindings_node/package.json b/bindings_node/package.json index 65db63a12..3aae68c7e 100644 --- a/bindings_node/package.json +++ b/bindings_node/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/node-bindings", - "version": "0.0.21", + "version": "0.0.22", "repository": { "type": "git", "url": "git+https://git@github.com/xmtp/libxmtp.git", diff --git a/bindings_node/src/client.rs b/bindings_node/src/client.rs index 3f042e501..2ca5f5c9f 100644 --- a/bindings_node/src/client.rs +++ b/bindings_node/src/client.rs @@ -13,7 +13,6 @@ use tracing_subscriber::{fmt, prelude::*}; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; -use xmtp_id::associations::verify_signed_with_public_context; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::LocalScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -123,7 +122,7 @@ fn init_logging(options: LogOptions) -> Result<()> { pub async fn create_client( host: String, is_secure: bool, - db_path: String, + db_path: Option, inbox_id: String, account_address: String, encryption_key: Option, @@ -135,7 +134,10 @@ pub async fn create_client( .await .map_err(|_| Error::from_reason("Error creating Tonic API client"))?; - let storage_option = StorageOption::Persistent(db_path); + let storage_option = match db_path { + Some(path) => StorageOption::Persistent(path), + None => StorageOption::Ephemeral, + }; let store = match encryption_key { Some(key) => { @@ -295,48 +297,4 @@ impl Client { .map_err(ErrorWrapper::from)?; Ok(state.into_iter().map(Into::into).collect()) } - - #[napi] - pub fn sign_with_installation_key(&self, signature_text: String) -> Result { - let result = self - .inner_client - .context() - .sign_with_public_context(signature_text) - .map_err(ErrorWrapper::from)?; - - Ok(result.into()) - } - - #[napi] - pub fn verify_signed_with_installation_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - ) -> Result<()> { - let public_key = self.inner_client().installation_public_key(); - self.verify_signed_with_public_key(signature_text, signature_bytes, public_key.into()) - } - - #[napi] - pub fn verify_signed_with_public_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - public_key: Uint8Array, - ) -> Result<()> { - let signature_bytes = signature_bytes.deref().to_vec(); - let signature_bytes: [u8; 64] = signature_bytes - .try_into() - .map_err(|_| Error::from_reason("signature_bytes is not 64 bytes long."))?; - - let public_key = public_key.deref().to_vec(); - let public_key: [u8; 32] = public_key - .try_into() - .map_err(|_| Error::from_reason("public_key is not 32 bytes long."))?; - - Ok( - verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) - .map_err(ErrorWrapper::from)?, - ) - } } diff --git a/bindings_node/src/signatures.rs b/bindings_node/src/signatures.rs index 709c374ec..d32ae8e5f 100644 --- a/bindings_node/src/signatures.rs +++ b/bindings_node/src/signatures.rs @@ -5,9 +5,31 @@ use napi_derive::napi; use std::ops::Deref; use xmtp_id::associations::{ unverified::{NewUnverifiedSmartContractWalletSignature, UnverifiedSignature}, - AccountId, + verify_signed_with_public_context, AccountId, }; +#[napi] +pub fn verify_signed_with_public_key( + signature_text: String, + signature_bytes: Uint8Array, + public_key: Uint8Array, +) -> Result<()> { + let signature_bytes = signature_bytes.deref().to_vec(); + let signature_bytes: [u8; 64] = signature_bytes + .try_into() + .map_err(|_| Error::from_reason("signature_bytes is not 64 bytes long."))?; + + let public_key = public_key.deref().to_vec(); + let public_key: [u8; 32] = public_key + .try_into() + .map_err(|_| Error::from_reason("public_key is not 32 bytes long."))?; + + Ok( + verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) + .map_err(ErrorWrapper::from)?, + ) +} + #[napi] #[derive(Eq, Hash, PartialEq)] pub enum SignatureRequestType { @@ -167,4 +189,25 @@ impl Client { Ok(()) } + + #[napi] + pub fn sign_with_installation_key(&self, signature_text: String) -> Result { + let result = self + .inner_client() + .context() + .sign_with_public_context(signature_text) + .map_err(ErrorWrapper::from)?; + + Ok(result.into()) + } + + #[napi] + pub fn verify_signed_with_installation_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + ) -> Result<()> { + let public_key = self.inner_client().installation_public_key(); + verify_signed_with_public_key(signature_text, signature_bytes, public_key.into()) + } } diff --git a/bindings_node/test/Client.test.ts b/bindings_node/test/Client.test.ts index 8942e7b25..ea84ea155 100644 --- a/bindings_node/test/Client.test.ts +++ b/bindings_node/test/Client.test.ts @@ -2,7 +2,12 @@ import { v4 } from 'uuid' import { toBytes } from 'viem' import { describe, expect, it } from 'vitest' import { createClient, createRegisteredClient, createUser } from '@test/helpers' -import { ConsentEntityType, ConsentState, SignatureRequestType } from '../dist' +import { + ConsentEntityType, + ConsentState, + SignatureRequestType, + verifySignedWithPublicKey, +} from '../dist' describe('Client', () => { it('should not be registered at first', async () => { @@ -224,5 +229,24 @@ describe('Client', () => { user2.account.address.toLowerCase(), ]) }) - it('should create client with structured logging', async () => {}) + + it('should sign and verify with installation key', async () => { + const user = createUser() + const client = await createRegisteredClient(user) + const text = 'gm!' + const signature = client.signWithInstallationKey(text) + expect(signature).toBeDefined() + expect(() => + client.verifySignedWithInstallationKey(text, signature) + ).not.toThrow() + expect(() => + client.verifySignedWithInstallationKey(text, new Uint8Array()) + ).toThrow() + expect(() => + verifySignedWithPublicKey(text, signature, client.installationIdBytes()) + ).not.toThrow() + expect(() => + verifySignedWithPublicKey(text, signature, new Uint8Array()) + ).toThrow() + }) }) diff --git a/bindings_wasm/CHANGELOG.md b/bindings_wasm/CHANGELOG.md index 69994bd9e..7755ac0c9 100644 --- a/bindings_wasm/CHANGELOG.md +++ b/bindings_wasm/CHANGELOG.md @@ -1,5 +1,9 @@ # @xmtp/wasm-bindings +## 0.0.7 + +- Moved `verify_signed_with_public_key` out of `Client` + ## 0.0.6 - Added `installation_id_bytes` to `Client` diff --git a/bindings_wasm/package.json b/bindings_wasm/package.json index d963f21e1..014358de6 100644 --- a/bindings_wasm/package.json +++ b/bindings_wasm/package.json @@ -1,6 +1,6 @@ { "name": "@xmtp/wasm-bindings", - "version": "0.0.6", + "version": "0.0.7", "type": "module", "license": "MIT", "description": "WASM bindings for the libXMTP rust library", diff --git a/bindings_wasm/src/client.rs b/bindings_wasm/src/client.rs index 13451ce22..be29aea38 100644 --- a/bindings_wasm/src/client.rs +++ b/bindings_wasm/src/client.rs @@ -11,7 +11,6 @@ use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::builder::SignatureRequest; -use xmtp_id::associations::verify_signed_with_public_context; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::groups::scoped_client::ScopedGroupClient; use xmtp_mls::identity::IdentityStrategy; @@ -125,7 +124,7 @@ pub async fn create_client( host: String, inbox_id: String, account_address: String, - db_path: String, + db_path: Option, encryption_key: Option, history_sync_url: Option, log_options: Option, @@ -134,7 +133,10 @@ pub async fn create_client( xmtp_mls::storage::init_sqlite().await; let api_client = XmtpHttpApiClient::new(host.clone()).unwrap(); - let storage_option = StorageOption::Persistent(db_path); + let storage_option = match db_path { + Some(path) => StorageOption::Persistent(path), + None => StorageOption::Ephemeral, + }; let store = match encryption_key { Some(key) => { @@ -284,50 +286,4 @@ impl Client { pub fn conversations(&self) -> Conversations { Conversations::new(self.inner_client.clone()) } - - #[wasm_bindgen(js_name = signWithInstallationKey)] - pub fn sign_with_installation_key(&self, signature_text: String) -> Result { - let result = self - .inner_client - .context() - .sign_with_public_context(signature_text) - .map_err(|e| JsError::new(format!("{}", e).as_str()))?; - - Ok(Uint8Array::from(result.as_slice())) - } - - #[wasm_bindgen(js_name = verifySignedWithInstallationKey)] - pub fn verify_signed_with_installation_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - ) -> Result<(), JsError> { - let public_key = self.inner_client().installation_public_key(); - self.verify_signed_with_public_key( - signature_text, - signature_bytes, - Uint8Array::from(public_key.as_slice()), - ) - } - - #[wasm_bindgen(js_name = verifySignedWithPublicKey)] - pub fn verify_signed_with_public_key( - &self, - signature_text: String, - signature_bytes: Uint8Array, - public_key: Uint8Array, - ) -> Result<(), JsError> { - let signature_bytes = signature_bytes.to_vec(); - let signature_bytes: [u8; 64] = signature_bytes - .try_into() - .map_err(|_| JsError::new("signature_bytes is not 64 bytes long."))?; - - let public_key = public_key.to_vec(); - let public_key: [u8; 32] = public_key - .try_into() - .map_err(|_| JsError::new("public_key is not 32 bytes long."))?; - - verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) - .map_err(|e| JsError::new(format!("{}", e).as_str())) - } } diff --git a/bindings_wasm/src/signatures.rs b/bindings_wasm/src/signatures.rs index 9fde22378..8265c88d0 100644 --- a/bindings_wasm/src/signatures.rs +++ b/bindings_wasm/src/signatures.rs @@ -1,5 +1,6 @@ use js_sys::Uint8Array; use wasm_bindgen::prelude::{wasm_bindgen, JsError}; +use xmtp_id::associations::verify_signed_with_public_context; use xmtp_id::associations::{ unverified::{NewUnverifiedSmartContractWalletSignature, UnverifiedSignature}, AccountId, @@ -7,6 +8,26 @@ use xmtp_id::associations::{ use crate::client::Client; +#[wasm_bindgen(js_name = verifySignedWithPublicKey)] +pub fn verify_signed_with_public_key( + signature_text: String, + signature_bytes: Uint8Array, + public_key: Uint8Array, +) -> Result<(), JsError> { + let signature_bytes = signature_bytes.to_vec(); + let signature_bytes: [u8; 64] = signature_bytes + .try_into() + .map_err(|_| JsError::new("signature_bytes is not 64 bytes long."))?; + + let public_key = public_key.to_vec(); + let public_key: [u8; 32] = public_key + .try_into() + .map_err(|_| JsError::new("public_key is not 32 bytes long."))?; + + verify_signed_with_public_context(signature_text, &signature_bytes, &public_key) + .map_err(|e| JsError::new(format!("{}", e).as_str())) +} + #[wasm_bindgen] #[derive(Clone, Eq, Hash, PartialEq)] pub enum SignatureRequestType { @@ -172,4 +193,29 @@ impl Client { Ok(()) } + + #[wasm_bindgen(js_name = signWithInstallationKey)] + pub fn sign_with_installation_key(&self, signature_text: String) -> Result { + let result = self + .inner_client() + .context() + .sign_with_public_context(signature_text) + .map_err(|e| JsError::new(format!("{}", e).as_str()))?; + + Ok(Uint8Array::from(result.as_slice())) + } + + #[wasm_bindgen(js_name = verifySignedWithInstallationKey)] + pub fn verify_signed_with_installation_key( + &self, + signature_text: String, + signature_bytes: Uint8Array, + ) -> Result<(), JsError> { + let public_key = self.inner_client().installation_public_key(); + verify_signed_with_public_key( + signature_text, + signature_bytes, + Uint8Array::from(public_key.as_slice()), + ) + } } diff --git a/bindings_wasm/tests/web.rs b/bindings_wasm/tests/web.rs index 32f6d02d6..afc323617 100644 --- a/bindings_wasm/tests/web.rs +++ b/bindings_wasm/tests/web.rs @@ -26,7 +26,7 @@ pub async fn test_create_client() { host.clone(), inbox_id.unwrap(), account_address.clone(), - "test".to_string(), + None, None, None, Some(LogOptions {