diff options
author | EnokMan <416828041@qq.com> | 2020-04-18 10:21:20 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-18 11:21:20 -0400 |
commit | 47617e60d551665ec509e013cfcae30987cb3b2b (patch) | |
tree | 5717061b7fd567b5fb8508f565993062f8014722 /cli/js | |
parent | 10469ec2798a7f02a6d9371207cc984502039bfa (diff) |
feat: startTLS (#4773)
Diffstat (limited to 'cli/js')
-rw-r--r-- | cli/js/deno.ts | 2 | ||||
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 27 | ||||
-rw-r--r-- | cli/js/ops/tls.ts | 14 | ||||
-rw-r--r-- | cli/js/tests/tls_test.ts | 51 | ||||
-rw-r--r-- | cli/js/tls.ts | 17 |
5 files changed, 108 insertions, 3 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts index 89795119b..0322bac27 100644 --- a/cli/js/deno.ts +++ b/cli/js/deno.ts @@ -106,7 +106,7 @@ export { resources, close } from "./ops/resources.ts"; export { signal, signals, Signal, SignalStream } from "./signals.ts"; export { FileInfo, statSync, lstatSync, stat, lstat } from "./ops/fs/stat.ts"; export { symlinkSync, symlink } from "./ops/fs/symlink.ts"; -export { connectTLS, listenTLS } from "./tls.ts"; +export { connectTLS, listenTLS, startTLS } from "./tls.ts"; export { truncateSync, truncate } from "./ops/fs/truncate.ts"; export { isatty, setRaw } from "./ops/tty.ts"; export { umask } from "./ops/fs/umask.ts"; diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index cdaff073b..9ab40248f 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -2038,6 +2038,33 @@ declare namespace Deno { */ export function connectTLS(options: ConnectTLSOptions): Promise<Conn>; + export interface StartTLSOptions { + /** A literal IP address or host name that can be resolved to an IP address. + * If not specified, defaults to `127.0.0.1`. */ + hostname?: string; + /** Server certificate file. */ + certFile?: string; + } + + /** **UNSTABLE**: new API, yet to be vetted. + * + * Start TLS handshake from an existing connection using + * an optional cert file, hostname (default is "127.0.0.1"). The + * cert file is optional and if not included Mozilla's root certificates will + * be used (see also https://github.com/ctz/webpki-roots for specifics) + * Using this function requires that the other end of the connection is + * prepared for TLS handshake. + * + * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" }); + * const tlsConn = await Deno.startTLS(conn, { certFile: "./certs/my_custom_root_CA.pem", hostname: "127.0.0.1", port: 80 }); + * + * Requires `allow-net` permission. + */ + export function startTLS( + conn: Conn, + options?: StartTLSOptions + ): Promise<Conn>; + /** **UNSTABLE**: not sure if broken or not */ export interface Metrics { opsDispatched: number; diff --git a/cli/js/ops/tls.ts b/cli/js/ops/tls.ts index 234e569dd..3964c44bb 100644 --- a/cli/js/ops/tls.ts +++ b/cli/js/ops/tls.ts @@ -8,7 +8,7 @@ export interface ConnectTLSRequest { certFile?: string; } -interface ConnectTLSResponse { +interface EstablishTLSResponse { rid: number; localAddr: { hostname: string; @@ -24,7 +24,7 @@ interface ConnectTLSResponse { export function connectTLS( args: ConnectTLSRequest -): Promise<ConnectTLSResponse> { +): Promise<EstablishTLSResponse> { return sendAsync("op_connect_tls", args); } @@ -66,3 +66,13 @@ interface ListenTLSResponse { export function listenTLS(args: ListenTLSRequest): ListenTLSResponse { return sendSync("op_listen_tls", args); } + +export interface StartTLSRequest { + rid: number; + hostname: string; + certFile?: string; +} + +export function startTLS(args: StartTLSRequest): Promise<EstablishTLSResponse> { + return sendAsync("op_start_tls", args); +} diff --git a/cli/js/tests/tls_test.ts b/cli/js/tests/tls_test.ts index 019b81652..e42e477c3 100644 --- a/cli/js/tests/tls_test.ts +++ b/cli/js/tests/tls_test.ts @@ -209,3 +209,54 @@ unitTest( await resolvable; } ); + +unitTest( + { perms: { read: true, net: true } }, + async function startTLS(): Promise<void> { + const hostname = "smtp.gmail.com"; + const port = 587; + const encoder = new TextEncoder(); + + let conn = await Deno.connect({ + hostname, + port, + }); + + let writer = new BufWriter(conn); + let reader = new TextProtoReader(new BufReader(conn)); + + let line: string | Deno.EOF = (await reader.readLine()) as string; + assert(line.startsWith("220")); + + await writer.write(encoder.encode(`EHLO ${hostname}\r\n`)); + await writer.flush(); + + while ((line = (await reader.readLine()) as string)) { + assert(line.startsWith("250")); + if (line.startsWith("250 ")) break; + } + + await writer.write(encoder.encode("STARTTLS\r\n")); + await writer.flush(); + + line = await reader.readLine(); + + // Received the message that the server is ready to establish TLS + assertEquals(line, "220 2.0.0 Ready to start TLS"); + + conn = await Deno.startTLS(conn, { hostname }); + writer = new BufWriter(conn); + reader = new TextProtoReader(new BufReader(conn)); + + // After that use TLS communication again + await writer.write(encoder.encode(`EHLO ${hostname}\r\n`)); + await writer.flush(); + + while ((line = (await reader.readLine()) as string)) { + assert(line.startsWith("250")); + if (line.startsWith("250 ")) break; + } + + conn.close(); + } +); diff --git a/cli/js/tls.ts b/cli/js/tls.ts index ef87b5aa1..f60eb24cb 100644 --- a/cli/js/tls.ts +++ b/cli/js/tls.ts @@ -57,3 +57,20 @@ export function listenTLS({ }); return new TLSListenerImpl(res.rid, res.localAddr); } + +interface StartTLSOptions { + hostname?: string; + certFile?: string; +} + +export async function startTLS( + conn: Conn, + { hostname = "127.0.0.1", certFile = undefined }: StartTLSOptions = {} +): Promise<Conn> { + const res = await tlsOps.startTLS({ + rid: conn.rid, + hostname, + certFile, + }); + return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!); +} |