From 32afc56005e2e9c8802a0fc57a537970794570cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 14 Feb 2024 09:57:34 +0100 Subject: [PATCH] ffi: Expose the method to add additional certs in the bindings --- .../src/authentication_service.rs | 15 ++++++++- bindings/matrix-sdk-ffi/src/client_builder.rs | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/bindings/matrix-sdk-ffi/src/authentication_service.rs b/bindings/matrix-sdk-ffi/src/authentication_service.rs index 544767856..8ed863d5f 100644 --- a/bindings/matrix-sdk-ffi/src/authentication_service.rs +++ b/bindings/matrix-sdk-ffi/src/authentication_service.rs @@ -26,7 +26,11 @@ use url::Url; use zeroize::Zeroize; use super::{client::Client, client_builder::ClientBuilder, RUNTIME}; -use crate::{client::ClientSessionDelegate, client_builder::UrlScheme, error::ClientError}; +use crate::{ + client::ClientSessionDelegate, + client_builder::{CertificateBytes, UrlScheme}, + error::ClientError, +}; #[derive(uniffi::Object)] pub struct AuthenticationService { @@ -39,6 +43,7 @@ pub struct AuthenticationService { custom_sliding_sync_proxy: RwLock>, cross_process_refresh_lock_id: Option, session_delegate: Option>, + additional_root_certificates: Vec, } impl Drop for AuthenticationService { @@ -176,10 +181,15 @@ impl HomeserverLoginDetails { impl AuthenticationService { /// Creates a new service to authenticate a user with. #[uniffi::constructor] + // TODO: This has too many arguments, even clippy agrees. Many of these methods are the same as + // for the `ClientBuilder`. We should let people pass in a `ClientBuilder` and possibly convert + // this to a builder pattern as well. + #[allow(clippy::too_many_arguments)] pub fn new( base_path: String, passphrase: Option, user_agent: Option, + additional_root_certificates: Vec>, oidc_configuration: Option, custom_sliding_sync_proxy: Option, session_delegate: Option>, @@ -195,6 +205,7 @@ impl AuthenticationService { custom_sliding_sync_proxy: RwLock::new(custom_sliding_sync_proxy), session_delegate: session_delegate.map(Into::into), cross_process_refresh_lock_id, + additional_root_certificates, }) } @@ -385,6 +396,8 @@ impl AuthenticationService { builder = builder.user_agent(user_agent); } + builder = builder.add_root_certificates(self.additional_root_certificates.clone()); + builder } diff --git a/bindings/matrix-sdk-ffi/src/client_builder.rs b/bindings/matrix-sdk-ffi/src/client_builder.rs index 596084e35..2e4daad89 100644 --- a/bindings/matrix-sdk-ffi/src/client_builder.rs +++ b/bindings/matrix-sdk-ffi/src/client_builder.rs @@ -2,6 +2,7 @@ use std::{fs, path::PathBuf, sync::Arc}; use matrix_sdk::{ encryption::{BackupDownloadStrategy, EncryptionSettings}, + reqwest::Certificate, ruma::{ api::{error::UnknownVersionError, MatrixVersion}, ServerName, UserId, @@ -15,6 +16,9 @@ use zeroize::Zeroizing; use super::{client::Client, RUNTIME}; use crate::{client::ClientSessionDelegate, error::ClientError, helpers::unwrap_or_clone_arc}; +/// A list of bytes containing a certificate in DER or PEM form. +pub type CertificateBytes = Vec; + #[derive(Clone)] pub(crate) enum UrlScheme { Http, @@ -37,6 +41,7 @@ pub struct ClientBuilder { inner: MatrixClientBuilder, cross_process_refresh_lock_id: Option, session_delegate: Option>, + additional_root_certificates: Vec>, } #[uniffi::export] @@ -62,6 +67,7 @@ impl ClientBuilder { }), cross_process_refresh_lock_id: None, session_delegate: None, + additional_root_certificates: Default::default(), }) } @@ -149,6 +155,16 @@ impl ClientBuilder { Arc::new(builder) } + pub fn add_root_certificates( + self: Arc, + certificates: Vec, + ) -> Arc { + let mut builder = unwrap_or_clone_arc(self); + builder.additional_root_certificates = certificates; + + Arc::new(builder) + } + pub fn build(self: Arc) -> Result, ClientError> { Ok(Arc::new(self.build_inner()?)) } @@ -224,6 +240,22 @@ impl ClientBuilder { ); } + let mut certificates = Vec::new(); + + for certificate in builder.additional_root_certificates { + // We don't really know what type of certificate we may get here, so let's try + // first one type, then the other. + if let Ok(cert) = Certificate::from_der(&certificate) { + certificates.push(cert); + } else { + let cert = Certificate::from_pem(&certificate) + .map_err(|e| anyhow::anyhow!("Failed to add a root certificate {e:?}"))?; + certificates.push(cert); + } + } + + inner_builder = inner_builder.add_root_certificates(certificates); + if let Some(proxy) = builder.proxy { inner_builder = inner_builder.proxy(proxy); }