summaryrefslogtreecommitdiff
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/fetch/Cargo.toml2
-rw-r--r--extensions/fetch/lib.rs78
-rw-r--r--extensions/net/Cargo.toml4
-rw-r--r--extensions/net/lib.rs12
-rw-r--r--extensions/net/ops_tls.rs128
-rw-r--r--extensions/tls/Cargo.toml24
-rw-r--r--extensions/tls/lib.rs129
-rw-r--r--extensions/websocket/Cargo.toml3
-rw-r--r--extensions/websocket/lib.rs31
9 files changed, 236 insertions, 175 deletions
diff --git a/extensions/fetch/Cargo.toml b/extensions/fetch/Cargo.toml
index 9c9a64222..211071236 100644
--- a/extensions/fetch/Cargo.toml
+++ b/extensions/fetch/Cargo.toml
@@ -17,8 +17,10 @@ path = "lib.rs"
bytes = "1.0.1"
data-url = "0.1.0"
deno_core = { version = "0.95.0", path = "../../core" }
+deno_tls = { version = "0.1.0", path = "../tls" }
deno_web = { version = "0.44.0", path = "../web" }
http = "0.2.4"
+lazy_static = "1.4.0"
reqwest = { version = "0.11.4", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] }
serde = { version = "1.0.126", features = ["derive"] }
tokio = { version = "1.8.1", features = ["full"] }
diff --git a/extensions/fetch/lib.rs b/extensions/fetch/lib.rs
index ad599b87c..0ac853cbc 100644
--- a/extensions/fetch/lib.rs
+++ b/extensions/fetch/lib.rs
@@ -1,7 +1,7 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+use data_url::DataUrl;
use deno_core::error::bad_resource_id;
-use deno_core::error::generic_error;
use deno_core::error::null_opbuf;
use deno_core::error::type_error;
use deno_core::error::AnyError;
@@ -24,16 +24,14 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
-
-use data_url::DataUrl;
+use deno_tls::create_http_client;
+use deno_tls::rustls::RootCertStore;
+use deno_tls::Proxy;
use deno_web::BlobStore;
use http::header::CONTENT_LENGTH;
-use reqwest::header::HeaderMap;
use reqwest::header::HeaderName;
use reqwest::header::HeaderValue;
use reqwest::header::HOST;
-use reqwest::header::USER_AGENT;
-use reqwest::redirect::Policy;
use reqwest::Body;
use reqwest::Client;
use reqwest::Method;
@@ -59,7 +57,7 @@ pub use reqwest; // Re-export reqwest
pub fn init<P: FetchPermissions + 'static>(
user_agent: String,
- ca_data: Option<Vec<u8>>,
+ root_cert_store: Option<RootCertStore>,
proxy: Option<Proxy>,
request_builder_hook: Option<fn(RequestBuilder) -> RequestBuilder>,
) -> Extension {
@@ -84,12 +82,17 @@ pub fn init<P: FetchPermissions + 'static>(
])
.state(move |state| {
state.put::<reqwest::Client>({
- create_http_client(user_agent.clone(), ca_data.clone(), proxy.clone())
- .unwrap()
+ create_http_client(
+ user_agent.clone(),
+ root_cert_store.clone(),
+ None,
+ proxy.clone(),
+ )
+ .unwrap()
});
state.put::<HttpClientDefaults>(HttpClientDefaults {
- ca_data: ca_data.clone(),
user_agent: user_agent.clone(),
+ root_cert_store: root_cert_store.clone(),
proxy: proxy.clone(),
request_builder_hook,
});
@@ -100,7 +103,7 @@ pub fn init<P: FetchPermissions + 'static>(
pub struct HttpClientDefaults {
pub user_agent: String,
- pub ca_data: Option<Vec<u8>>,
+ pub root_cert_store: Option<RootCertStore>,
pub proxy: Option<Proxy>,
pub request_builder_hook: Option<fn(RequestBuilder) -> RequestBuilder>,
}
@@ -501,26 +504,12 @@ impl HttpClientResource {
#[serde(rename_all = "camelCase")]
#[serde(default)]
pub struct CreateHttpClientOptions {
+ ca_stores: Option<Vec<String>>,
ca_file: Option<String>,
ca_data: Option<ByteString>,
proxy: Option<Proxy>,
}
-#[derive(Deserialize, Default, Debug, Clone)]
-#[serde(rename_all = "camelCase")]
-#[serde(default)]
-pub struct Proxy {
- pub url: String,
- pub basic_auth: Option<BasicAuth>,
-}
-
-#[derive(Deserialize, Default, Debug, Clone)]
-#[serde(default)]
-pub struct BasicAuth {
- pub username: String,
- pub password: String,
-}
-
pub fn op_create_http_client<FP>(
state: &mut OpState,
args: CreateHttpClientOptions,
@@ -541,12 +530,12 @@ where
}
let defaults = state.borrow::<HttpClientDefaults>();
-
let cert_data =
get_cert_data(args.ca_file.as_deref(), args.ca_data.as_deref())?;
let client = create_http_client(
defaults.user_agent.clone(),
- cert_data.or_else(|| defaults.ca_data.clone()),
+ defaults.root_cert_store.clone(),
+ cert_data,
args.proxy,
)
.unwrap();
@@ -569,36 +558,3 @@ fn get_cert_data(
Ok(None)
}
}
-
-/// Create new instance of async reqwest::Client. This client supports
-/// proxies and doesn't follow redirects.
-pub fn create_http_client(
- user_agent: String,
- ca_data: Option<Vec<u8>>,
- proxy: Option<Proxy>,
-) -> Result<Client, AnyError> {
- let mut headers = HeaderMap::new();
- headers.insert(USER_AGENT, user_agent.parse().unwrap());
- let mut builder = Client::builder()
- .redirect(Policy::none())
- .default_headers(headers)
- .use_rustls_tls();
-
- if let Some(ca_data) = ca_data {
- let cert = reqwest::Certificate::from_pem(&ca_data)?;
- builder = builder.add_root_certificate(cert);
- }
-
- if let Some(proxy) = proxy {
- let mut reqwest_proxy = reqwest::Proxy::all(&proxy.url)?;
- if let Some(basic_auth) = &proxy.basic_auth {
- reqwest_proxy =
- reqwest_proxy.basic_auth(&basic_auth.username, &basic_auth.password);
- }
- builder = builder.proxy(reqwest_proxy);
- }
-
- builder
- .build()
- .map_err(|e| generic_error(format!("Unable to build http client: {}", e)))
-}
diff --git a/extensions/net/Cargo.toml b/extensions/net/Cargo.toml
index d774acf88..58363fd2e 100644
--- a/extensions/net/Cargo.toml
+++ b/extensions/net/Cargo.toml
@@ -15,13 +15,11 @@ path = "lib.rs"
[dependencies]
deno_core = { version = "0.95.0", path = "../../core" }
+deno_tls = { version = "0.1.0", path = "../tls" }
lazy_static = "1.4.0"
log = "0.4.14"
-rustls = "0.19.0"
serde = { version = "1.0.126", features = ["derive"] }
tokio = { version = "1.8.1", features = ["full"] }
trust-dns-proto = "0.20.3"
trust-dns-resolver = { version = "0.20.3", features = ["tokio-runtime", "serde-config"] }
-webpki = "0.21.4"
-webpki-roots = "0.21.1"
diff --git a/extensions/net/lib.rs b/extensions/net/lib.rs
index 11d0b4493..6b0b728b1 100644
--- a/extensions/net/lib.rs
+++ b/extensions/net/lib.rs
@@ -11,6 +11,7 @@ use deno_core::error::AnyError;
use deno_core::include_js_files;
use deno_core::Extension;
use deno_core::OpState;
+use deno_tls::rustls::RootCertStore;
use std::cell::RefCell;
use std::path::Path;
use std::path::PathBuf;
@@ -90,20 +91,17 @@ pub fn get_unstable_declaration() -> PathBuf {
#[derive(Clone)]
pub struct DefaultTlsOptions {
- pub ca_data: Option<Vec<u8>>,
+ pub root_cert_store: Option<RootCertStore>,
}
pub fn init<P: NetPermissions + 'static>(
- ca_data: Option<Vec<u8>>,
+ root_cert_store: Option<RootCertStore>,
unstable: bool,
) -> Extension {
let mut ops_to_register = vec![];
ops_to_register.extend(io::init());
ops_to_register.extend(ops::init::<P>());
ops_to_register.extend(ops_tls::init::<P>());
-
- let default_tls_options = DefaultTlsOptions { ca_data };
-
Extension::builder()
.js(include_js_files!(
prefix "deno:extensions/net",
@@ -113,7 +111,9 @@ pub fn init<P: NetPermissions + 'static>(
))
.ops(ops_to_register)
.state(move |state| {
- state.put(default_tls_options.clone());
+ state.put(DefaultTlsOptions {
+ root_cert_store: root_cert_store.clone(),
+ });
state.put(UnstableChecker { unstable });
Ok(())
})
diff --git a/extensions/net/ops_tls.rs b/extensions/net/ops_tls.rs
index a082f7f62..124da2f03 100644
--- a/extensions/net/ops_tls.rs
+++ b/extensions/net/ops_tls.rs
@@ -1,8 +1,5 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-pub use rustls;
-pub use webpki;
-
use crate::io::TcpStreamResource;
use crate::io::TlsStreamResource;
use crate::ops::IpAddr;
@@ -38,30 +35,29 @@ use deno_core::OpState;
use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
+use deno_tls::create_client_config;
+use deno_tls::rustls::internal::pemfile::certs;
+use deno_tls::rustls::internal::pemfile::pkcs8_private_keys;
+use deno_tls::rustls::internal::pemfile::rsa_private_keys;
+use deno_tls::rustls::Certificate;
+use deno_tls::rustls::ClientConfig;
+use deno_tls::rustls::ClientSession;
+use deno_tls::rustls::NoClientAuth;
+use deno_tls::rustls::PrivateKey;
+use deno_tls::rustls::ServerConfig;
+use deno_tls::rustls::ServerSession;
+use deno_tls::rustls::Session;
+use deno_tls::webpki::DNSNameRef;
use io::Error;
use io::Read;
use io::Write;
-use rustls::internal::pemfile::certs;
-use rustls::internal::pemfile::pkcs8_private_keys;
-use rustls::internal::pemfile::rsa_private_keys;
-use rustls::Certificate;
-use rustls::ClientConfig;
-use rustls::ClientSession;
-use rustls::NoClientAuth;
-use rustls::PrivateKey;
-use rustls::ServerConfig;
-use rustls::ServerSession;
-use rustls::Session;
-use rustls::StoresClientSessions;
use serde::Deserialize;
use std::borrow::Cow;
use std::cell::RefCell;
-use std::collections::HashMap;
use std::convert::From;
use std::fs::File;
use std::io;
use std::io::BufReader;
-use std::io::Cursor;
use std::io::ErrorKind;
use std::ops::Deref;
use std::ops::DerefMut;
@@ -76,32 +72,6 @@ use tokio::io::ReadBuf;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
use tokio::task::spawn_local;
-use webpki::DNSNameRef;
-
-lazy_static::lazy_static! {
- static ref CLIENT_SESSION_MEMORY_CACHE: Arc<ClientSessionMemoryCache> =
- Arc::new(ClientSessionMemoryCache::default());
-}
-
-#[derive(Default)]
-struct ClientSessionMemoryCache(Mutex<HashMap<Vec<u8>, Vec<u8>>>);
-
-impl StoresClientSessions for ClientSessionMemoryCache {
- fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
- self.0.lock().get(key).cloned()
- }
-
- fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool {
- let mut sessions = self.0.lock();
- // TODO(bnoordhuis) Evict sessions LRU-style instead of arbitrarily.
- while sessions.len() >= 1024 {
- let key = sessions.keys().next().unwrap().clone();
- sessions.remove(&key);
- }
- sessions.insert(key, value);
- true
- }
-}
#[derive(Debug)]
enum TlsSession {
@@ -703,8 +673,6 @@ where
n => n,
};
let cert_file = args.cert_file.as_deref();
-
- let default_tls_options;
{
super::check_unstable2(&state, "Deno.startTls");
let mut s = state.borrow_mut();
@@ -713,12 +681,28 @@ where
if let Some(path) = cert_file {
permissions.check_read(Path::new(path))?;
}
- default_tls_options = s.borrow::<DefaultTlsOptions>().clone();
}
+ let ca_data = match cert_file {
+ Some(path) => {
+ let mut buf = Vec::new();
+ File::open(path)?.read_to_end(&mut buf)?;
+ Some(buf)
+ }
+ _ => None,
+ };
+
let hostname_dns = DNSNameRef::try_from_ascii_str(hostname)
.map_err(|_| invalid_hostname(hostname))?;
+ // TODO(@justinmchase): Ideally the certificate store is created once
+ // and not cloned. The store should be wrapped in Arc<T> to reduce
+ // copying memory unnecessarily.
+ let root_cert_store = state
+ .borrow()
+ .borrow::<DefaultTlsOptions>()
+ .root_cert_store
+ .clone();
let resource_rc = state
.borrow_mut()
.resource_table
@@ -732,22 +716,7 @@ where
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
- let mut tls_config = ClientConfig::new();
- tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone());
- tls_config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(ca_data) = default_tls_options.ca_data {
- let reader = &mut Cursor::new(ca_data);
- tls_config.root_store.add_pem_file(reader).unwrap();
- };
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- tls_config.root_store.add_pem_file(reader).unwrap();
- }
- let tls_config = Arc::new(tls_config);
-
+ let tls_config = Arc::new(create_client_config(root_cert_store, ca_data)?);
let tls_stream =
TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns);
@@ -786,8 +755,6 @@ where
};
let port = args.port;
let cert_file = args.cert_file.as_deref();
-
- let default_tls_options;
{
let mut s = state.borrow_mut();
let permissions = s.borrow_mut::<NP>();
@@ -795,9 +762,22 @@ where
if let Some(path) = cert_file {
permissions.check_read(Path::new(path))?;
}
- default_tls_options = s.borrow::<DefaultTlsOptions>().clone();
}
+ let ca_data = match cert_file {
+ Some(path) => {
+ let mut buf = Vec::new();
+ File::open(path)?.read_to_end(&mut buf)?;
+ Some(buf)
+ }
+ _ => None,
+ };
+
+ let root_cert_store = state
+ .borrow()
+ .borrow::<DefaultTlsOptions>()
+ .root_cert_store
+ .clone();
let hostname_dns = DNSNameRef::try_from_ascii_str(hostname)
.map_err(|_| invalid_hostname(hostname))?;
@@ -808,23 +788,7 @@ where
let tcp_stream = TcpStream::connect(connect_addr).await?;
let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?;
-
- let mut tls_config = ClientConfig::new();
- tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone());
- tls_config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
- if let Some(ca_data) = default_tls_options.ca_data {
- let reader = &mut Cursor::new(ca_data);
- tls_config.root_store.add_pem_file(reader).unwrap();
- };
- if let Some(path) = cert_file {
- let key_file = File::open(path)?;
- let reader = &mut BufReader::new(key_file);
- tls_config.root_store.add_pem_file(reader).unwrap();
- }
- let tls_config = Arc::new(tls_config);
-
+ let tls_config = Arc::new(create_client_config(root_cert_store, ca_data)?);
let tls_stream =
TlsStream::new_client_side(tcp_stream, &tls_config, hostname_dns);
diff --git a/extensions/tls/Cargo.toml b/extensions/tls/Cargo.toml
new file mode 100644
index 000000000..ee7be04dc
--- /dev/null
+++ b/extensions/tls/Cargo.toml
@@ -0,0 +1,24 @@
+# Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+[package]
+name = "deno_tls"
+version = "0.1.0"
+authors = ["the Deno authors"]
+edition = "2018"
+license = "MIT"
+readme = "README.md"
+repository = "https://github.com/denoland/deno"
+description = "TLS for Deno"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+deno_core = { version = "0.95.0", path = "../../core" }
+lazy_static = "1.4.0"
+reqwest = { version = "0.11.4", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] }
+rustls = "0.19.0"
+rustls-native-certs = "0.5.0"
+serde = { version = "1.0.126", features = ["derive"] }
+webpki = "0.21.4"
+webpki-roots = "0.21.1"
diff --git a/extensions/tls/lib.rs b/extensions/tls/lib.rs
new file mode 100644
index 000000000..f91249792
--- /dev/null
+++ b/extensions/tls/lib.rs
@@ -0,0 +1,129 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+
+pub use reqwest;
+pub use rustls;
+pub use rustls_native_certs;
+pub use webpki;
+pub use webpki_roots;
+
+use deno_core::error::anyhow;
+use deno_core::error::generic_error;
+use deno_core::error::AnyError;
+use deno_core::parking_lot::Mutex;
+use deno_core::Extension;
+
+use reqwest::header::HeaderMap;
+use reqwest::header::USER_AGENT;
+use reqwest::redirect::Policy;
+use reqwest::Client;
+use rustls::ClientConfig;
+use rustls::RootCertStore;
+use rustls::StoresClientSessions;
+use serde::Deserialize;
+use std::collections::HashMap;
+use std::io::BufReader;
+use std::io::Cursor;
+use std::sync::Arc;
+
+/// This extension has no runtime apis, it only exports some shared native functions.
+pub fn init() -> Extension {
+ Extension::builder().build()
+}
+
+#[derive(Deserialize, Default, Debug, Clone)]
+#[serde(rename_all = "camelCase")]
+#[serde(default)]
+pub struct Proxy {
+ pub url: String,
+ pub basic_auth: Option<BasicAuth>,
+}
+
+#[derive(Deserialize, Default, Debug, Clone)]
+#[serde(default)]
+pub struct BasicAuth {
+ pub username: String,
+ pub password: String,
+}
+
+lazy_static::lazy_static! {
+ static ref CLIENT_SESSION_MEMORY_CACHE: Arc<ClientSessionMemoryCache> =
+ Arc::new(ClientSessionMemoryCache::default());
+}
+
+#[derive(Default)]
+struct ClientSessionMemoryCache(Mutex<HashMap<Vec<u8>, Vec<u8>>>);
+
+impl StoresClientSessions for ClientSessionMemoryCache {
+ fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
+ self.0.lock().get(key).cloned()
+ }
+
+ fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool {
+ let mut sessions = self.0.lock();
+ // TODO(bnoordhuis) Evict sessions LRU-style instead of arbitrarily.
+ while sessions.len() >= 1024 {
+ let key = sessions.keys().next().unwrap().clone();
+ sessions.remove(&key);
+ }
+ sessions.insert(key, value);
+ true
+ }
+}
+
+pub fn create_default_root_cert_store() -> RootCertStore {
+ let mut root_cert_store = RootCertStore::empty();
+ // TODO(@justinmchase): Consider also loading the system keychain here
+ root_cert_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
+ root_cert_store
+}
+
+pub fn create_client_config(
+ root_cert_store: Option<RootCertStore>,
+ ca_data: Option<Vec<u8>>,
+) -> Result<ClientConfig, AnyError> {
+ let mut tls_config = ClientConfig::new();
+ tls_config.set_persistence(CLIENT_SESSION_MEMORY_CACHE.clone());
+ tls_config.root_store =
+ root_cert_store.unwrap_or_else(create_default_root_cert_store);
+
+ // If a custom cert is specified, add it to the store
+ if let Some(cert) = ca_data {
+ let reader = &mut BufReader::new(Cursor::new(cert));
+ // This function does not return specific errors, if it fails give a generic message.
+ if let Err(_err) = tls_config.root_store.add_pem_file(reader) {
+ return Err(anyhow!("Unable to add pem file to certificate store"));
+ }
+ }
+
+ Ok(tls_config)
+}
+
+/// Create new instance of async reqwest::Client. This client supports
+/// proxies and doesn't follow redirects.
+pub fn create_http_client(
+ user_agent: String,
+ root_cert_store: Option<RootCertStore>,
+ ca_data: Option<Vec<u8>>,
+ proxy: Option<Proxy>,
+) -> Result<Client, AnyError> {
+ let tls_config = create_client_config(root_cert_store, ca_data)?;
+ let mut headers = HeaderMap::new();
+ headers.insert(USER_AGENT, user_agent.parse().unwrap());
+ let mut builder = Client::builder()
+ .redirect(Policy::none())
+ .default_headers(headers)
+ .use_preconfigured_tls(tls_config);
+
+ if let Some(proxy) = proxy {
+ let mut reqwest_proxy = reqwest::Proxy::all(&proxy.url)?;
+ if let Some(basic_auth) = &proxy.basic_auth {
+ reqwest_proxy =
+ reqwest_proxy.basic_auth(&basic_auth.username, &basic_auth.password);
+ }
+ builder = builder.proxy(reqwest_proxy);
+ }
+
+ builder
+ .build()
+ .map_err(|e| generic_error(format!("Unable to build http client: {}", e)))
+}
diff --git a/extensions/websocket/Cargo.toml b/extensions/websocket/Cargo.toml
index 3e1705950..1e01c2691 100644
--- a/extensions/websocket/Cargo.toml
+++ b/extensions/websocket/Cargo.toml
@@ -15,11 +15,10 @@ path = "lib.rs"
[dependencies]
deno_core = { version = "0.95.0", path = "../../core" }
+deno_tls = { version = "0.1.0", path = "../tls" }
http = "0.2.4"
hyper = { version = "0.14.9" }
serde = { version = "1.0.126", features = ["derive"] }
tokio = { version = "1.8.1", features = ["full"] }
tokio-rustls = "0.22.0"
tokio-tungstenite = { version = "0.14.0", features = ["rustls-tls"] }
-webpki = "0.21.4"
-webpki-roots = "0.21.1"
diff --git a/extensions/websocket/lib.rs b/extensions/websocket/lib.rs
index f5bf15c79..01f0a523d 100644
--- a/extensions/websocket/lib.rs
+++ b/extensions/websocket/lib.rs
@@ -22,31 +22,31 @@ use deno_core::RcRef;
use deno_core::Resource;
use deno_core::ResourceId;
use deno_core::ZeroCopyBuf;
+use deno_tls::create_client_config;
+use deno_tls::webpki::DNSNameRef;
use http::{Method, Request, Uri};
use serde::Deserialize;
use serde::Serialize;
use std::borrow::Cow;
use std::cell::RefCell;
-use std::io::BufReader;
-use std::io::Cursor;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use tokio::net::TcpStream;
-use tokio_rustls::{rustls::ClientConfig, TlsConnector};
+use tokio_rustls::rustls::RootCertStore;
+use tokio_rustls::TlsConnector;
use tokio_tungstenite::tungstenite::{
handshake::client::Response, protocol::frame::coding::CloseCode,
protocol::CloseFrame, Message,
};
use tokio_tungstenite::MaybeTlsStream;
use tokio_tungstenite::{client_async, WebSocketStream};
-use webpki::DNSNameRef;
pub use tokio_tungstenite; // Re-export tokio_tungstenite
#[derive(Clone)]
-pub struct WsCaData(pub Vec<u8>);
+pub struct WsRootStore(pub Option<RootCertStore>);
#[derive(Clone)]
pub struct WsUserAgent(pub String);
@@ -197,7 +197,7 @@ where
);
}
- let ws_ca_data = state.borrow().try_borrow::<WsCaData>().cloned();
+ let root_cert_store = state.borrow().borrow::<WsRootStore>().0.clone();
let user_agent = state.borrow().borrow::<WsUserAgent>().0.clone();
let uri: Uri = args.url.parse()?;
let mut request = Request::builder().method(Method::GET).uri(&uri);
@@ -221,17 +221,8 @@ where
let socket: MaybeTlsStream<TcpStream> = match uri.scheme_str() {
Some("ws") => MaybeTlsStream::Plain(tcp_socket),
Some("wss") => {
- let mut config = ClientConfig::new();
- config
- .root_store
- .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
-
- if let Some(ws_ca_data) = ws_ca_data {
- let reader = &mut BufReader::new(Cursor::new(ws_ca_data.0));
- config.root_store.add_pem_file(reader).unwrap();
- }
-
- let tls_connector = TlsConnector::from(Arc::new(config));
+ let tls_config = create_client_config(root_cert_store, None)?;
+ let tls_connector = TlsConnector::from(Arc::new(tls_config));
let dnsname = DNSNameRef::try_from_ascii_str(domain)
.map_err(|_| invalid_hostname(domain))?;
let tls_socket = tls_connector.connect(dnsname, tcp_socket).await?;
@@ -385,7 +376,7 @@ pub async fn op_ws_next_event(
pub fn init<P: WebSocketPermissions + 'static>(
user_agent: String,
- ca_data: Option<Vec<u8>>,
+ root_cert_store: Option<RootCertStore>,
) -> Extension {
Extension::builder()
.js(include_js_files!(
@@ -404,9 +395,7 @@ pub fn init<P: WebSocketPermissions + 'static>(
])
.state(move |state| {
state.put::<WsUserAgent>(WsUserAgent(user_agent.clone()));
- if let Some(ca_data) = ca_data.clone() {
- state.put::<WsCaData>(WsCaData(ca_data));
- }
+ state.put::<WsRootStore>(WsRootStore(root_cert_store.clone()));
Ok(())
})
.build()