diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index 01d2ff2e14..c87cd744c6 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -1220,12 +1220,6 @@ declare namespace Deno { * The options used when creating a [HttpClient]. */ interface CreateHttpClientOptions { - /** A certificate authority to use when validating TLS certificates. - * - * Requires `allow-read` permission. - */ - caFile?: string; - /** A certificate authority to use when validating TLS certificates. Certificate data must be PEM encoded. */ caData?: string; diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index 52e9cc8007..55251dbd03 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -283,14 +283,14 @@ impl FileFetcher { http_cache: HttpCache, cache_setting: CacheSetting, allow_remote: bool, - maybe_ca_file: Option<&str>, + maybe_ca_data: Option<&str>, ) -> Result { Ok(Self { allow_remote, cache: FileCache::default(), cache_setting, http_cache, - http_client: create_http_client(get_user_agent(), maybe_ca_file)?, + http_client: create_http_client(get_user_agent(), maybe_ca_data)?, }) } diff --git a/cli/http_util.rs b/cli/http_util.rs index f6f8095a06..cedaa1d0e3 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -14,8 +14,6 @@ use deno_runtime::deno_fetch::reqwest::redirect::Policy; use deno_runtime::deno_fetch::reqwest::Client; use deno_runtime::deno_fetch::reqwest::StatusCode; use std::collections::HashMap; -use std::fs::File; -use std::io::Read; pub fn get_user_agent() -> String { format!("Deno/{}", version::deno()) @@ -25,7 +23,7 @@ pub fn get_user_agent() -> String { /// proxies and doesn't follow redirects. pub fn create_http_client( user_agent: String, - ca_file: Option<&str>, + ca_data: Option<&str>, ) -> Result { let mut headers = HeaderMap::new(); headers.insert(USER_AGENT, user_agent.parse().unwrap()); @@ -34,10 +32,9 @@ pub fn create_http_client( .default_headers(headers) .use_rustls_tls(); - if let Some(ca_file) = ca_file { - let mut buf = Vec::new(); - File::open(ca_file)?.read_to_end(&mut buf)?; - let cert = reqwest::Certificate::from_pem(&buf)?; + if let Some(ca_data) = ca_data { + let ca_data_vec = ca_data.as_bytes().to_vec(); + let cert = reqwest::Certificate::from_pem(&ca_data_vec)?; builder = builder.add_root_certificate(cert); } @@ -159,9 +156,10 @@ pub async fn fetch_once( #[cfg(test)] mod tests { use super::*; + use std::fs::read_to_string; - fn create_test_client(ca_file: Option<&str>) -> Client { - create_http_client("test_client".to_string(), ca_file).unwrap() + fn create_test_client(ca_data: Option<&str>) -> Client { + create_http_client("test_client".to_string(), ca_data).unwrap() } #[tokio::test] @@ -314,17 +312,12 @@ mod tests { // Relies on external http server. See target/debug/test_server let url = Url::parse("https://localhost:5545/cli/tests/fixture.json").unwrap(); - - let client = create_http_client( - get_user_agent(), - Some( - test_util::root_path() - .join("std/http/testdata/tls/RootCA.pem") - .to_str() - .unwrap(), - ), + let ca_data: String = read_to_string( + test_util::root_path().join("std/http/testdata/tls/RootCA.pem"), ) .unwrap(); + let client = + create_http_client(get_user_agent(), Some(ca_data.as_str())).unwrap(); let result = fetch_once(client, &url, None).await; if let Ok(FetchOnceResult::Code(body, headers)) = result { assert!(!body.is_empty()); @@ -344,16 +337,12 @@ mod tests { "https://localhost:5545/cli/tests/053_import_compression/gziped", ) .unwrap(); - let client = create_http_client( - get_user_agent(), - Some( - test_util::root_path() - .join("std/http/testdata/tls/RootCA.pem") - .to_str() - .unwrap(), - ), + let ca_data: String = read_to_string( + test_util::root_path().join("std/http/testdata/tls/RootCA.pem"), ) .unwrap(); + let client = + create_http_client(get_user_agent(), Some(ca_data.as_str())).unwrap(); let result = fetch_once(client, &url, None).await; if let Ok(FetchOnceResult::Code(body, headers)) = result { assert_eq!(String::from_utf8(body).unwrap(), "console.log('gzip')"); @@ -372,16 +361,12 @@ mod tests { async fn test_fetch_with_cafile_with_etag() { let _http_server_guard = test_util::http_server(); let url = Url::parse("https://localhost:5545/etag_script.ts").unwrap(); - let client = create_http_client( - get_user_agent(), - Some( - test_util::root_path() - .join("std/http/testdata/tls/RootCA.pem") - .to_str() - .unwrap(), - ), + let ca_data: String = read_to_string( + test_util::root_path().join("std/http/testdata/tls/RootCA.pem"), ) .unwrap(); + let client = + create_http_client(get_user_agent(), Some(ca_data.as_str())).unwrap(); let result = fetch_once(client.clone(), &url, None).await; if let Ok(FetchOnceResult::Code(body, headers)) = result { assert!(!body.is_empty()); @@ -409,16 +394,12 @@ mod tests { "https://localhost:5545/cli/tests/053_import_compression/brotli", ) .unwrap(); - let client = create_http_client( - get_user_agent(), - Some( - test_util::root_path() - .join("std/http/testdata/tls/RootCA.pem") - .to_str() - .unwrap(), - ), + let ca_data: String = read_to_string( + test_util::root_path().join("std/http/testdata/tls/RootCA.pem"), ) .unwrap(); + let client = + create_http_client(get_user_agent(), Some(ca_data.as_str())).unwrap(); let result = fetch_once(client, &url, None).await; if let Ok(FetchOnceResult::Code(body, headers)) = result { assert!(!body.is_empty()); diff --git a/cli/program_state.rs b/cli/program_state.rs index e55386fe58..3000b355de 100644 --- a/cli/program_state.rs +++ b/cli/program_state.rs @@ -25,6 +25,7 @@ use deno_core::ModuleSource; use deno_core::ModuleSpecifier; use std::collections::HashMap; use std::env; +use std::fs::read_to_string; use std::sync::Arc; use std::sync::Mutex; @@ -58,7 +59,13 @@ impl ProgramState { let dir = deno_dir::DenoDir::new(custom_root)?; let deps_cache_location = dir.root.join("deps"); let http_cache = http_cache::HttpCache::new(&deps_cache_location); - let ca_file = flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); + let ca_file_path = + flags.ca_file.clone().or_else(|| env::var("DENO_CERT").ok()); + + let ca_data: Option = match ca_file_path.as_ref() { + None => None, + Some(ca_file_path) => Some(read_to_string(ca_file_path)?), + }; let cache_usage = if flags.cached_only { CacheSetting::Only @@ -74,7 +81,7 @@ impl ProgramState { http_cache, cache_usage, !flags.no_remote, - ca_file.as_deref(), + ca_data.as_deref(), )?; let lockfile = if let Some(filename) = &flags.lock { diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts index 85792b2030..e5389d0240 100644 --- a/cli/tests/unit/fetch_test.ts +++ b/cli/tests/unit/fetch_test.ts @@ -1010,24 +1010,6 @@ unitTest(function fetchResponseEmptyConstructor(): void { assertEquals([...response.headers], []); }); -unitTest( - { perms: { net: true, read: true } }, - async function fetchCustomHttpClientFileCertificateSuccess(): Promise< - void - > { - const client = Deno.createHttpClient( - { caFile: "./cli/tests/tls/RootCA.crt" }, - ); - const response = await fetch( - "https://localhost:5545/cli/tests/fixture.json", - { client }, - ); - const json = await response.json(); - assertEquals(json.name, "deno"); - client.close(); - }, -); - unitTest( { perms: { net: true } }, async function fetchCustomHttpClientParamCertificateSuccess(): Promise<