diff options
Diffstat (limited to 'cli/tests/unit/tls_test.ts')
-rw-r--r-- | cli/tests/unit/tls_test.ts | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/cli/tests/unit/tls_test.ts b/cli/tests/unit/tls_test.ts new file mode 100644 index 000000000..3d071441d --- /dev/null +++ b/cli/tests/unit/tls_test.ts @@ -0,0 +1,262 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + assert, + assertEquals, + createResolvable, + unitTest, +} from "./test_util.ts"; +import { BufWriter, BufReader } from "../../../std/io/bufio.ts"; +import { TextProtoReader } from "../../../std/textproto/mod.ts"; + +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +unitTest(async function connectTLSNoPerm(): Promise<void> { + let err; + try { + await Deno.connectTls({ hostname: "github.com", port: 443 }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest(async function connectTLSCertFileNoReadPerm(): Promise<void> { + let err; + try { + await Deno.connectTls({ + hostname: "github.com", + port: 443, + certFile: "cli/tests/tls/RootCA.crt", + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { read: true, net: true } }, + function listenTLSNonExistentCertKeyFiles(): void { + let err; + const options = { + hostname: "localhost", + port: 3500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key", + }; + + try { + Deno.listenTls({ + ...options, + certFile: "./non/existent/file", + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + + try { + Deno.listenTls({ + ...options, + keyFile: "./non/existent/file", + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest({ perms: { net: true } }, function listenTLSNoReadPerm(): void { + let err; + try { + Deno.listenTls({ + hostname: "localhost", + port: 3500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key", + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { + perms: { read: true, write: true, net: true }, + }, + function listenTLSEmptyKeyFile(): void { + let err; + const options = { + hostname: "localhost", + port: 3500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key", + }; + + const testDir = Deno.makeTempDirSync(); + const keyFilename = testDir + "/key.pem"; + Deno.writeFileSync(keyFilename, new Uint8Array([]), { + mode: 0o666, + }); + + try { + Deno.listenTls({ + ...options, + keyFile: keyFilename, + }); + } catch (e) { + err = e; + } + assert(err instanceof Error); + } +); + +unitTest( + { perms: { read: true, write: true, net: true } }, + function listenTLSEmptyCertFile(): void { + let err; + const options = { + hostname: "localhost", + port: 3500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key", + }; + + const testDir = Deno.makeTempDirSync(); + const certFilename = testDir + "/cert.crt"; + Deno.writeFileSync(certFilename, new Uint8Array([]), { + mode: 0o666, + }); + + try { + Deno.listenTls({ + ...options, + certFile: certFilename, + }); + } catch (e) { + err = e; + } + assert(err instanceof Error); + } +); + +unitTest( + { perms: { read: true, net: true } }, + async function dialAndListenTLS(): Promise<void> { + const resolvable = createResolvable(); + const hostname = "localhost"; + const port = 3500; + + const listener = Deno.listenTls({ + hostname, + port, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key", + }); + + const response = encoder.encode( + "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n" + ); + + listener.accept().then( + async (conn): Promise<void> => { + assert(conn.remoteAddr != null); + assert(conn.localAddr != null); + await conn.write(response); + // TODO(bartlomieju): this might be a bug + setTimeout(() => { + conn.close(); + resolvable.resolve(); + }, 0); + } + ); + + const conn = await Deno.connectTls({ + hostname, + port, + certFile: "cli/tests/tls/RootCA.pem", + }); + assert(conn.rid > 0); + const w = new BufWriter(conn); + const r = new BufReader(conn); + const body = `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`; + const writeResult = await w.write(encoder.encode(body)); + assertEquals(body.length, writeResult); + await w.flush(); + const tpr = new TextProtoReader(r); + const statusLine = await tpr.readLine(); + assert(statusLine !== null, `line must be read: ${String(statusLine)}`); + const m = statusLine.match(/^(.+?) (.+?) (.+?)$/); + assert(m !== null, "must be matched"); + const [_, proto, status, ok] = m; + assertEquals(proto, "HTTP/1.1"); + assertEquals(status, "200"); + assertEquals(ok, "OK"); + const headers = await tpr.readMIMEHeader(); + assert(headers !== null); + const contentLength = parseInt(headers.get("content-length")!); + const bodyBuf = new Uint8Array(contentLength); + await r.readFull(bodyBuf); + assertEquals(decoder.decode(bodyBuf), "Hello World\n"); + conn.close(); + listener.close(); + 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 | null = (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(); + } +); |