mirror of
https://github.com/denoland/deno.git
synced 2025-01-12 17:09:00 -05:00
feat(unstable): ALPN config in listenTls (#10065)
This commit adds the ability for users to configure ALPN protocols when calling `Deno.listenTls`.
This commit is contained in:
parent
1c6602b85b
commit
8d55d8b6be
5 changed files with 115 additions and 0 deletions
10
cli/dts/lib.deno.unstable.d.ts
vendored
10
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -1001,6 +1001,16 @@ declare namespace Deno {
|
||||||
options?: StartTlsOptions,
|
options?: StartTlsOptions,
|
||||||
): Promise<Conn>;
|
): Promise<Conn>;
|
||||||
|
|
||||||
|
export interface ListenTlsOptions {
|
||||||
|
/** **UNSTABLE**: new API, yet to be vetted.
|
||||||
|
*
|
||||||
|
* Application-Layer Protocol Negotiation (ALPN) protocols to announce to
|
||||||
|
* the client. If not specified, no ALPN extension will be included in the
|
||||||
|
* TLS handshake.
|
||||||
|
*/
|
||||||
|
alpnProtocols?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
/** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal
|
/** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal
|
||||||
* enum.
|
* enum.
|
||||||
*
|
*
|
||||||
|
|
|
@ -5,11 +5,17 @@ use deno_core::serde_json;
|
||||||
use deno_core::url;
|
use deno_core::url;
|
||||||
use deno_runtime::deno_fetch::reqwest;
|
use deno_runtime::deno_fetch::reqwest;
|
||||||
use deno_runtime::deno_websocket::tokio_tungstenite;
|
use deno_runtime::deno_websocket::tokio_tungstenite;
|
||||||
|
use rustls::Session;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io::Cursor;
|
||||||
use std::io::{BufRead, Read, Write};
|
use std::io::{BufRead, Read, Write};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::sync::Arc;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use test_util as util;
|
use test_util as util;
|
||||||
|
use tokio_rustls::rustls;
|
||||||
|
use tokio_rustls::webpki;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn js_unit_tests_lint() {
|
fn js_unit_tests_lint() {
|
||||||
|
@ -5879,3 +5885,82 @@ console.log("finish");
|
||||||
handle.abort();
|
handle.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn listen_tls_alpn() {
|
||||||
|
let child = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("--quiet")
|
||||||
|
.arg("--allow-net")
|
||||||
|
.arg("--allow-read")
|
||||||
|
.arg("./cli/tests/listen_tls_alpn.ts")
|
||||||
|
.arg("4504")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
let mut stdout = child.stdout.unwrap();
|
||||||
|
let mut buffer = [0; 5];
|
||||||
|
let read = stdout.read(&mut buffer).unwrap();
|
||||||
|
assert_eq!(read, 5);
|
||||||
|
let msg = std::str::from_utf8(&buffer).unwrap();
|
||||||
|
assert_eq!(msg, "READY");
|
||||||
|
|
||||||
|
let mut cfg = rustls::ClientConfig::new();
|
||||||
|
let reader =
|
||||||
|
&mut BufReader::new(Cursor::new(include_bytes!("./tls/RootCA.crt")));
|
||||||
|
cfg.root_store.add_pem_file(reader).unwrap();
|
||||||
|
cfg.alpn_protocols.push("foobar".as_bytes().to_vec());
|
||||||
|
|
||||||
|
let tls_connector = tokio_rustls::TlsConnector::from(Arc::new(cfg));
|
||||||
|
let hostname = webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap();
|
||||||
|
let stream = tokio::net::TcpStream::connect("localhost:4504")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let tls_stream = tls_connector.connect(hostname, stream).await.unwrap();
|
||||||
|
let (_, session) = tls_stream.get_ref();
|
||||||
|
|
||||||
|
let alpn = session.get_alpn_protocol().unwrap();
|
||||||
|
assert_eq!(std::str::from_utf8(alpn).unwrap(), "foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn listen_tls_alpn_fail() {
|
||||||
|
let child = util::deno_cmd()
|
||||||
|
.current_dir(util::root_path())
|
||||||
|
.arg("run")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("--quiet")
|
||||||
|
.arg("--allow-net")
|
||||||
|
.arg("--allow-read")
|
||||||
|
.arg("./cli/tests/listen_tls_alpn.ts")
|
||||||
|
.arg("4505")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
let mut stdout = child.stdout.unwrap();
|
||||||
|
let mut buffer = [0; 5];
|
||||||
|
let read = stdout.read(&mut buffer).unwrap();
|
||||||
|
assert_eq!(read, 5);
|
||||||
|
let msg = std::str::from_utf8(&buffer).unwrap();
|
||||||
|
assert_eq!(msg, "READY");
|
||||||
|
|
||||||
|
let mut cfg = rustls::ClientConfig::new();
|
||||||
|
let reader =
|
||||||
|
&mut BufReader::new(Cursor::new(include_bytes!("./tls/RootCA.crt")));
|
||||||
|
cfg.root_store.add_pem_file(reader).unwrap();
|
||||||
|
cfg.alpn_protocols.push("boofar".as_bytes().to_vec());
|
||||||
|
|
||||||
|
let tls_connector = tokio_rustls::TlsConnector::from(Arc::new(cfg));
|
||||||
|
let hostname = webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap();
|
||||||
|
let stream = tokio::net::TcpStream::connect("localhost:4505")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let tls_stream = tls_connector.connect(hostname, stream).await.unwrap();
|
||||||
|
let (_, session) = tls_stream.get_ref();
|
||||||
|
|
||||||
|
assert!(session.get_alpn_protocol().is_none());
|
||||||
|
}
|
||||||
|
|
12
cli/tests/listen_tls_alpn.ts
Normal file
12
cli/tests/listen_tls_alpn.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
const listener = Deno.listenTls({
|
||||||
|
port: Number(Deno.args[0]),
|
||||||
|
certFile: "./cli/tests/tls/localhost.crt",
|
||||||
|
keyFile: "./cli/tests/tls/localhost.key",
|
||||||
|
alpnProtocols: ["h2", "http/1.1", "foobar"],
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("READY");
|
||||||
|
|
||||||
|
for await (const conn of listener) {
|
||||||
|
conn.close();
|
||||||
|
}
|
|
@ -51,6 +51,7 @@
|
||||||
keyFile,
|
keyFile,
|
||||||
hostname = "0.0.0.0",
|
hostname = "0.0.0.0",
|
||||||
transport = "tcp",
|
transport = "tcp",
|
||||||
|
alpnProtocols,
|
||||||
}) {
|
}) {
|
||||||
const res = opListenTls({
|
const res = opListenTls({
|
||||||
port,
|
port,
|
||||||
|
@ -58,6 +59,7 @@
|
||||||
keyFile,
|
keyFile,
|
||||||
hostname,
|
hostname,
|
||||||
transport,
|
transport,
|
||||||
|
alpnProtocols,
|
||||||
});
|
});
|
||||||
return new TLSListener(res.rid, res.localAddr);
|
return new TLSListener(res.rid, res.localAddr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,6 +300,7 @@ pub struct ListenTlsArgs {
|
||||||
port: u16,
|
port: u16,
|
||||||
cert_file: String,
|
cert_file: String,
|
||||||
key_file: String,
|
key_file: String,
|
||||||
|
alpn_protocols: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_listen_tls(
|
fn op_listen_tls(
|
||||||
|
@ -318,6 +319,11 @@ fn op_listen_tls(
|
||||||
permissions.read.check(Path::new(&key_file))?;
|
permissions.read.check(Path::new(&key_file))?;
|
||||||
}
|
}
|
||||||
let mut config = ServerConfig::new(NoClientAuth::new());
|
let mut config = ServerConfig::new(NoClientAuth::new());
|
||||||
|
if let Some(alpn_protocols) = args.alpn_protocols {
|
||||||
|
super::check_unstable(state, "Deno.listenTls#alpn_protocols");
|
||||||
|
config.alpn_protocols =
|
||||||
|
alpn_protocols.into_iter().map(|s| s.into_bytes()).collect();
|
||||||
|
}
|
||||||
config
|
config
|
||||||
.set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0))
|
.set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0))
|
||||||
.expect("invalid key or certificate");
|
.expect("invalid key or certificate");
|
||||||
|
|
Loading…
Reference in a new issue