1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 00:29:09 -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:
Luca Casonato 2021-04-10 22:04:44 +02:00 committed by GitHub
parent 1c6602b85b
commit 8d55d8b6be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 0 deletions

View file

@ -1001,6 +1001,16 @@ declare namespace Deno {
options?: StartTlsOptions,
): 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
* enum.
*

View file

@ -5,11 +5,17 @@ use deno_core::serde_json;
use deno_core::url;
use deno_runtime::deno_fetch::reqwest;
use deno_runtime::deno_websocket::tokio_tungstenite;
use rustls::Session;
use std::fs;
use std::io::BufReader;
use std::io::Cursor;
use std::io::{BufRead, Read, Write};
use std::process::Command;
use std::sync::Arc;
use tempfile::TempDir;
use test_util as util;
use tokio_rustls::rustls;
use tokio_rustls::webpki;
#[test]
fn js_unit_tests_lint() {
@ -5879,3 +5885,82 @@ console.log("finish");
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());
}

View 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();
}

View file

@ -51,6 +51,7 @@
keyFile,
hostname = "0.0.0.0",
transport = "tcp",
alpnProtocols,
}) {
const res = opListenTls({
port,
@ -58,6 +59,7 @@
keyFile,
hostname,
transport,
alpnProtocols,
});
return new TLSListener(res.rid, res.localAddr);
}

View file

@ -300,6 +300,7 @@ pub struct ListenTlsArgs {
port: u16,
cert_file: String,
key_file: String,
alpn_protocols: Option<Vec<String>>,
}
fn op_listen_tls(
@ -318,6 +319,11 @@ fn op_listen_tls(
permissions.read.check(Path::new(&key_file))?;
}
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
.set_single_cert(load_certs(&cert_file)?, load_keys(&key_file)?.remove(0))
.expect("invalid key or certificate");