summaryrefslogtreecommitdiff
path: root/cli/js
diff options
context:
space:
mode:
authorEnokMan <416828041@qq.com>2020-04-18 10:21:20 -0500
committerGitHub <noreply@github.com>2020-04-18 11:21:20 -0400
commit47617e60d551665ec509e013cfcae30987cb3b2b (patch)
tree5717061b7fd567b5fb8508f565993062f8014722 /cli/js
parent10469ec2798a7f02a6d9371207cc984502039bfa (diff)
feat: startTLS (#4773)
Diffstat (limited to 'cli/js')
-rw-r--r--cli/js/deno.ts2
-rw-r--r--cli/js/lib.deno.ns.d.ts27
-rw-r--r--cli/js/ops/tls.ts14
-rw-r--r--cli/js/tests/tls_test.ts51
-rw-r--r--cli/js/tls.ts17
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!);
+}