diff options
author | Jonathon Orsi <jonathon.orsi@gmail.com> | 2019-09-23 14:40:38 -0400 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2019-09-23 15:12:42 -0400 |
commit | 045e74bb39d7743b774cfd2b889bc6ce1e1ad245 (patch) | |
tree | 93a8429860a40eabaee813e6f983f64aebd8afc7 /cli | |
parent | 4ff04ad96f27b7073e3478630ed249eedc76af2b (diff) |
feat: Add Deno.dialTLS()
Co-authored-by: Bartek IwaĆczuk <biwanczuk@gmail.com>
Diffstat (limited to 'cli')
-rw-r--r-- | cli/Cargo.toml | 2 | ||||
-rw-r--r-- | cli/ops/mod.rs | 5 | ||||
-rw-r--r-- | cli/ops/tls.rs | 76 | ||||
-rw-r--r-- | cli/resources.rs | 13 |
4 files changed, 96 insertions, 0 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml index b9a9c1456..463c9fbc1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -56,6 +56,8 @@ tokio-rustls = "0.10.0" tokio-threadpool = "0.1.15" url = "1.7.2" utime = "0.2.1" +webpki = "0.21.0" +webpki-roots = "0.17.0" [target.'cfg(windows)'.dependencies] winapi = "0.3.8" diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index 7a2e9c9f4..ea71fee9f 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -20,6 +20,7 @@ mod random; mod repl; mod resources; mod timers; +mod tls; mod workers; // Warning! These values are duplicated in the TypeScript code (js/dispatch.ts), @@ -81,6 +82,7 @@ pub const OP_TRUNCATE: OpId = 54; pub const OP_MAKE_TEMP_DIR: OpId = 55; pub const OP_CWD: OpId = 56; pub const OP_FETCH_ASSET: OpId = 57; +pub const OP_DIAL_TLS: OpId = 58; pub fn dispatch( state: &ThreadSafeState, @@ -300,6 +302,9 @@ pub fn dispatch( control, zero_copy, ), + OP_DIAL_TLS => { + dispatch_json::dispatch(tls::op_dial_tls, state, control, zero_copy) + } _ => panic!("bad op_id"), }; diff --git a/cli/ops/tls.rs b/cli/ops/tls.rs new file mode 100644 index 000000000..2b1d94f2b --- /dev/null +++ b/cli/ops/tls.rs @@ -0,0 +1,76 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +use super::dispatch_json::{Deserialize, JsonOp, Value}; +use crate::resolve_addr::resolve_addr; +use crate::resources; +use crate::state::ThreadSafeState; +use deno::*; +use futures::Future; +use std; +use std::convert::From; +use std::sync::Arc; +use tokio; +use tokio::net::TcpStream; +use tokio_rustls::{rustls::ClientConfig, TlsConnector}; +use webpki; +use webpki::DNSNameRef; +use webpki_roots; + +#[derive(Deserialize)] +struct DialTLSArgs { + hostname: String, + port: u16, +} + +pub fn op_dial_tls( + state: &ThreadSafeState, + args: Value, + _zero_copy: Option<PinnedBuf>, +) -> Result<JsonOp, ErrBox> { + let args: DialTLSArgs = serde_json::from_value(args)?; + + // TODO(ry) Using format! is suboptimal here. Better would be if + // state.check_net and resolve_addr() took hostname and port directly. + let address = format!("{}:{}", args.hostname, args.port); + + state.check_net(&address)?; + + let mut domain = args.hostname; + if domain.is_empty() { + domain.push_str("localhost"); + } + + let op = resolve_addr(&address).and_then(move |addr| { + TcpStream::connect(&addr) + .and_then(move |tcp_stream| { + let local_addr = tcp_stream.local_addr()?; + let remote_addr = tcp_stream.peer_addr()?; + let mut config = ClientConfig::new(); + config + .root_store + .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); + + let tls_connector = TlsConnector::from(Arc::new(config)); + Ok((tls_connector, tcp_stream, local_addr, remote_addr)) + }) + .map_err(ErrBox::from) + .and_then( + move |(tls_connector, tcp_stream, local_addr, remote_addr)| { + let dnsname = DNSNameRef::try_from_ascii_str(&domain) + .expect("Invalid DNS lookup"); + tls_connector + .connect(dnsname, tcp_stream) + .map_err(ErrBox::from) + .and_then(move |tls_stream| { + let tls_stream_resource = resources::add_tls_stream(tls_stream); + futures::future::ok(json!({ + "rid": tls_stream_resource.rid, + "localAddr": local_addr.to_string(), + "remoteAddr": remote_addr.to_string(), + })) + }) + }, + ) + }); + + Ok(JsonOp::Async(Box::new(op))) +} diff --git a/cli/resources.rs b/cli/resources.rs index 3bce51afb..0fdb0e182 100644 --- a/cli/resources.rs +++ b/cli/resources.rs @@ -36,6 +36,7 @@ use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::TcpStream; use tokio::sync::mpsc; use tokio_process; +use tokio_rustls::client::TlsStream; pub type ResourceId = u32; // Sometimes referred to RID. @@ -89,6 +90,7 @@ enum Repr { // See: https://github.com/tokio-rs/tokio/issues/846 TcpListener(tokio::net::TcpListener, Option<futures::task::Task>), TcpStream(tokio::net::TcpStream), + TlsStream(Box<TlsStream<TcpStream>>), HttpBody(HttpBody), Repl(Arc<Mutex<Repl>>), // Enum size is bounded by the largest variant. @@ -134,6 +136,7 @@ fn inspect_repr(repr: &Repr) -> String { Repr::FsFile(_) => "fsFile", Repr::TcpListener(_, _) => "tcpListener", Repr::TcpStream(_) => "tcpStream", + Repr::TlsStream(_) => "tlsStream", Repr::HttpBody(_) => "httpBody", Repr::Repl(_) => "repl", Repr::Child(_) => "child", @@ -249,6 +252,7 @@ impl DenoAsyncRead for Resource { Repr::FsFile(ref mut f) => f.poll_read(buf), Repr::Stdin(ref mut f) => f.poll_read(buf), Repr::TcpStream(ref mut f) => f.poll_read(buf), + Repr::TlsStream(ref mut f) => f.poll_read(buf), Repr::HttpBody(ref mut f) => f.poll_read(buf), Repr::ChildStdout(ref mut f) => f.poll_read(buf), Repr::ChildStderr(ref mut f) => f.poll_read(buf), @@ -289,6 +293,7 @@ impl DenoAsyncWrite for Resource { Repr::Stdout(ref mut f) => f.poll_write(buf), Repr::Stderr(ref mut f) => f.poll_write(buf), Repr::TcpStream(ref mut f) => f.poll_write(buf), + Repr::TlsStream(ref mut f) => f.poll_write(buf), Repr::ChildStdin(ref mut f) => f.poll_write(buf), _ => { return Err(bad_resource()); @@ -332,6 +337,14 @@ pub fn add_tcp_stream(stream: tokio::net::TcpStream) -> Resource { Resource { rid } } +pub fn add_tls_stream(stream: TlsStream<TcpStream>) -> Resource { + let rid = new_rid(); + let mut tg = RESOURCE_TABLE.lock().unwrap(); + let r = tg.insert(rid, Repr::TlsStream(Box::new(stream))); + assert!(r.is_none()); + Resource { rid } +} + pub fn add_reqwest_body(body: ReqwestDecoder) -> Resource { let rid = new_rid(); let mut tg = RESOURCE_TABLE.lock().unwrap(); |