fix(node/tls): implement secureConnect event (#2926)

This commit is contained in:
Yoshiya Hinosawa 2022-11-26 05:01:50 +09:00 committed by GitHub
parent f04499970b
commit 9f1974dd1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 196 additions and 41 deletions

View File

@ -48,7 +48,7 @@
"lint:check-assertions": "deno run --allow-read --allow-net ./_tools/check_assertions.ts",
"lint": "deno lint && deno task node:lint-circular-deps && deno task lint:licence-headers && deno task lint:deprecations && deno task lint:doc-imports && deno task lint:check-assertions",
"node:lint-circular-deps": "deno run --allow-read --allow-net=deno.land ./node/_tools/check_circular_deps.ts",
"node:unit": "deno test --unstable --allow-all node/ --ignore=node/_tools/test.ts,node/_tools/versions/",
"node:unit": "deno test --unstable --allow-all --unsafely-ignore-certificate-errors node/ --ignore=node/_tools/test.ts,node/_tools/versions/",
"node:test": "deno test --unstable --allow-all node/_tools/test.ts",
"node:setup": "deno run --allow-read --allow-net --allow-write node/_tools/setup.ts",
"node:check-unstable-api": "deno check --unstable ./node/module_all.ts",

View File

@ -20,14 +20,15 @@ import {
} from "./internal_binding/pipe_wrap.ts";
import { EventEmitter } from "./events.ts";
import { kEmptyObject } from "./internal/util.mjs";
import { nextTick } from "./_next_tick.ts";
const kConnectOptions = Symbol("connect-options");
const kIsVerified = Symbol("verified");
const kPendingSession = Symbol("pendingSession");
const kRes = Symbol("res");
let _debug = debuglog("tls", (fn) => {
_debug = fn;
let debug = debuglog("tls", (fn) => {
debug = fn;
});
function onConnectEnd(this: any) {
@ -233,14 +234,14 @@ export class ServerImpl extends EventEmitter {
}
listen(port: any, callback: any): this {
const { key, cert } = this.options;
// TODO(kt3k): Get this from optional 2nd argument.
const hostname = "localhost";
const key = this.options.key?.toString();
const cert = this.options.cert?.toString();
// TODO(kt3k): The default host should be "localhost"
const hostname = this.options.host ?? "0.0.0.0";
this.listener = Deno.listenTls({ port, hostname, cert, key });
callback?.();
callback?.call(this);
this.#listen(this.listener);
return this;
}
@ -268,8 +269,19 @@ export class ServerImpl extends EventEmitter {
this.listener.close();
}
cb?.();
nextTick(() => {
this.emit("close");
});
return this;
}
address() {
const addr = this.listener!.addr as Deno.NetAddr;
return {
port: addr.port,
address: addr.hostname,
};
}
}
Server.prototype = ServerImpl.prototype;
@ -278,6 +290,15 @@ export function createServer(options: any, listener: any) {
return new ServerImpl(options, listener);
}
function onConnectSecure(this: TLSSocket) {
this.authorized = true;
this.secureConnecting = false;
debug("client emit secureConnect. authorized:", this.authorized);
this.emit("secureConnect");
this.removeListener("end", onConnectEnd);
}
export function connect(...args: any[]) {
args = normalizeConnectArgs(args);
let options = args[0];
@ -373,6 +394,7 @@ export function connect(...args: any[]) {
tlssock._start();
}
tlssock.on("secure", onConnectSecure);
tlssock.prependListener("end", onConnectEnd);
return tlssock;
@ -413,5 +435,6 @@ export default {
createServer,
checkServerIdentity,
DEFAULT_CIPHERS,
Server,
unfqdn,
};

View File

@ -2101,7 +2101,6 @@ Total: 2825
- [parallel/test-tls-connect-no-host.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-no-host.js)
- [parallel/test-tls-connect-pipe.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-pipe.js)
- [parallel/test-tls-connect-secure-context.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-secure-context.js)
- [parallel/test-tls-connect-simple.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-simple.js)
- [parallel/test-tls-connect-stream-writes.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-stream-writes.js)
- [parallel/test-tls-connect-timeout-option.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-connect-timeout-option.js)
- [parallel/test-tls-delayed-attach-error.js](https://github.com/nodejs/node/tree/v18.12.0/test/parallel/test-tls-delayed-attach-error.js)

View File

@ -113,6 +113,10 @@
"loop.js",
"x.txt"
],
"fixtures/keys": [
"agent1-cert.pem",
"agent1-key.pem"
],
"internet": [
"test-dgram-connect.js",
"test-dns-any.js",
@ -672,6 +676,7 @@
"test-timers-unref-throw-then-ref.js",
"test-timers-user-call.js",
"test-timers-zero-timeout.js",
"test-tls-connect-simple.js",
"test-url-fileurltopath.js",
"test-url-format-invalid-input.js",
"test-url-format-whatwg.js",

View File

@ -54,26 +54,17 @@ if (USE_CACHE) {
CACHE_MODE = "prompt";
}
const NODE_URL = "https://nodejs.org/dist/vNODE_VERSION";
const NODE_FILE = "node-vNODE_VERSION";
const NODE_URL = "https://nodejs.org/dist/v" + config.nodeVersion;
const NODE_FILE = "node-v" + config.nodeVersion;
const NODE_ARCHIVE_FILE = `${NODE_FILE}.tar.gz`;
const NATIVE_NODE_TESTS_FOLDER = "/test";
/** URL for the download */
const url = `${NODE_URL}/${NODE_ARCHIVE_FILE}`.replaceAll(
"NODE_VERSION",
config.nodeVersion,
);
const url = `${NODE_URL}/${NODE_ARCHIVE_FILE}`;
/** Local archive's url location */
const archivePath = join(
config.versionsFolder,
NODE_ARCHIVE_FILE.replaceAll("NODE_VERSION", config.nodeVersion),
);
const archivePath = join(config.versionsFolder, NODE_ARCHIVE_FILE);
/** Local decompressed source's location */
const decompressedSourcePath = join(
config.versionsFolder,
NODE_FILE.replaceAll("NODE_VERSION", config.nodeVersion),
);
const decompressedSourcePath = join(config.versionsFolder, NODE_FILE);
function checkConfigTestFilesOrder(testFileLists: Array<string[]>) {
for (const testFileList of testFileLists) {
@ -119,10 +110,7 @@ async function decompressTests(archivePath: string) {
const tar = new Untar(buffer);
const outFolder = dirname(fromFileUrl(new URL(archivePath, import.meta.url)));
const testsFolder = `${NODE_FILE}${NATIVE_NODE_TESTS_FOLDER}`.replace(
"NODE_VERSION",
config.nodeVersion,
);
const testsFolder = `${NODE_FILE}${NATIVE_NODE_TESTS_FOLDER}`;
for await (const entry of tar) {
if (entry.type !== "file") continue;
@ -170,7 +158,12 @@ async function copyTests(filePath: string) {
);
for await (const entry of walk(path, { skip: ignoreList })) {
const expectedSuite = dirname(entry.path).split(sep).at(-1)!;
const fragments = entry.path.split(sep);
// Note: When the path is, for example,
// "/path/to/deno_std/node/_tools/versions/node-v18.12.0/test/fixtures/policy/main.mjs"
// then expectedSuite becomes "fixtures/policy" (The folder after "test" becomes "suite")
const expectedSuite = fragments.slice(fragments.indexOf(NODE_FILE) + 2, -1)
.join("/");
const suite = getRequestedFileSuite(entry.name, expectedSuite);
if (!suite) continue;

View File

@ -61,7 +61,7 @@ for await (const path of testPaths) {
"-A",
"--quiet",
"--unstable",
"--no-check",
"--unsafely-ignore-certificate-errors",
"--v8-flags=" + v8Flags.join(),
targetTestPath.endsWith(".mjs")
? "--import-map=" + importMap

View File

@ -0,0 +1,30 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 18.12.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
-----BEGIN CERTIFICATE-----
MIID6DCCAtCgAwIBAgIUFH02wcL3Qgben6tfIibXitsApCYwDQYJKoZIhvcNAQEL
BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEPMA0G
A1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQDDANjYTExIDAe
BgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMCAXDTIyMDkwMzIxNDAzN1oY
DzIyOTYwNjE3MjE0MDM3WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJ
BgNVBAcMAlNGMQ8wDQYDVQQKDAZKb3llbnQxEDAOBgNVBAsMB05vZGUuanMxDzAN
BgNVBAMMBmFnZW50MTEgMB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUVjIK+yDTgnCT3CxChO0E
37q9VuHdrlKeKLeQzUJW2yczSfNzX/0zfHpjY+zKWie39z3HCJqWxtiG2wxiOI8c
3WqWOvzVmdWADlh6EfkIlg+E7VC6JaKDA+zabmhPvnuu3JzogBMnsWl68lCXzuPx
deQAmEwNtqjrh74DtM+Ud0ulb//Ixjxo1q3rYKu+aaexSramuee6qJta2rjrB4l8
B/bU+j1mDf9XQQfSjo9jRnp4hiTFdBl2k+lZzqE2L/rhu6EMjA2IhAq/7xA2MbLo
9cObVUin6lfoo5+JKRgT9Fp2xEgDOit+2EA/S6oUfPNeLSVUqmXOSWlXlwlb9Nxr
AgMBAAGjYTBfMF0GCCsGAQUFBwEBBFEwTzAjBggrBgEFBQcwAYYXaHR0cDovL29j
c3Aubm9kZWpzLm9yZy8wKAYIKwYBBQUHMAKGHGh0dHA6Ly9jYS5ub2RlanMub3Jn
L2NhLmNlcnQwDQYJKoZIhvcNAQELBQADggEBAMM0mBBjLMt9pYXePtUeNO0VTw9y
FWCM8nAcAO2kRNwkJwcsispNpkcsHZ5o8Xf5mpCotdvziEWG1hyxwU6nAWyNOLcN
G0a0KUfbMO3B6ZYe1GwPDjXaQnv75SkAdxgX5zOzca3xnhITcjUUGjQ0fbDfwFV5
ix8mnzvfXjDONdEznVa7PFcN6QliFUMwR/h8pCRHtE5+a10OSPeJSrGG+FtrGnRW
G1IJUv6oiGF/MvWCr84REVgc1j78xomGANJIu2hN7bnD1nEMON6em8IfnDOUtynV
9wfWTqiQYD5Zifj6WcGa0aAHMuetyFG4lIfMAHmd3gaKpks7j9l26LwRPvI=
-----END CERTIFICATE-----

View File

@ -0,0 +1,34 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 18.12.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1FYyCvsg04Jwk9wsQoTtBN+6vVbh3a5Snii3kM1CVtsnM0nz
c1/9M3x6Y2Psylont/c9xwialsbYhtsMYjiPHN1qljr81ZnVgA5YehH5CJYPhO1Q
uiWigwPs2m5oT757rtyc6IATJ7FpevJQl87j8XXkAJhMDbao64e+A7TPlHdLpW//
yMY8aNat62CrvmmnsUq2prnnuqibWtq46weJfAf21Po9Zg3/V0EH0o6PY0Z6eIYk
xXQZdpPpWc6hNi/64buhDIwNiIQKv+8QNjGy6PXDm1VIp+pX6KOfiSkYE/RadsRI
AzorfthAP0uqFHzzXi0lVKplzklpV5cJW/TcawIDAQABAoIBAAvbtHfAhpjJVBgt
15rvaX04MWmZjIugzKRgib/gdq/7FTlcC+iJl85kSUF7tyGl30n62MxgwqFhAX6m
hQ6HMhbelrFFIhGbwbyhEHfgwROlrcAysKt0pprCgVvBhrnNXYLqdyjU3jz9P3LK
TY3s0/YMK2uNFdI+PTjKH+Z9Foqn9NZUnUonEDepGyuRO7fLeccWJPv2L4CR4a/5
ku4VbDgVpvVSVRG3PSVzbmxobnpdpl52og+T7tPx1cLnIknPtVljXPWtZdfekh2E
eAp2KxCCHOKzzG3ItBKsVu0woeqEpy8JcoO6LbgmEoVnZpgmtQClbBgef8+i+oGE
BgW9nmECgYEA8gA63QQuZOUC56N1QXURexN2PogF4wChPaCTFbQSJXvSBkQmbqfL
qRSD8P0t7GOioPrQK6pDwFf4BJB01AvkDf8Z6DxxOJ7cqIC7LOwDupXocWX7Q0Qk
O6cwclBVsrDZK00v60uRRpl/a39GW2dx7IiQDkKQndLh3/0TbMIWHNcCgYEA4J6r
yinZbLpKw2+ezhi4B4GT1bMLoKboJwpZVyNZZCzYR6ZHv+lS7HR/02rcYMZGoYbf
n7OHwF4SrnUS7vPhG4g2ZsOhKQnMvFSQqpGmK1ZTuoKGAevyvtouhK/DgtLWzGvX
9fSahiq/UvfXs/z4M11q9Rv9ztPCmG1cwSEHlo0CgYEAogQNZJK8DMhVnYcNpXke
7uskqtCeQE/Xo06xqkIYNAgloBRYNpUYAGa/vsOBz1UVN/kzDUi8ezVp0oRz8tLT
J5u2WIi+tE2HJTiqF3UbOfvK1sCT64DfUSCpip7GAQ/tFNRkVH8PD9kMOYfILsGe
v+DdsO5Xq5HXrwHb02BNNZkCgYBsl8lt33WiPx5OBfS8pu6xkk+qjPkeHhM2bKZs
nkZlS9j0KsudWGwirN/vkkYg8zrKdK5AQ0dqFRDrDuasZ3N5IA1M+V88u+QjWK7o
B6pSYVXxYZDv9OZSpqC+vUrEQLJf+fNakXrzSk9dCT1bYv2Lt6ox/epix7XYg2bI
Z/OHMQKBgQC2FUGhlndGeugTJaoJ8nhT/0VfRUX/h6sCgSerk5qFr/hNCBV4T022
x0NDR2yLG6MXyqApJpG6rh3QIDElQoQCNlI3/KJ6JfEfmqrLLN2OigTvA5sE4fGU
Dp/ha8OQAx95EwXuaG7LgARduvOIK3x8qi8KsZoUGJcg2ywurUbkWA==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,69 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 18.12.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const tls = require('tls');
const fixtures = require('../common/fixtures');
let serverConnected = 0;
const options = {
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem')
};
const server = tls.Server(options, common.mustCall(function(socket) {
if (++serverConnected === 2) {
server.close(common.mustCall());
server.on('close', common.mustCall());
}
}, 2));
server.listen(0, function() {
const client1options = {
port: this.address().port,
rejectUnauthorized: false
};
const client1 = tls.connect(client1options, common.mustCall(function() {
client1.end();
}));
const client2options = {
port: this.address().port,
rejectUnauthorized: false
};
const client2 = tls.connect(client2options);
client2.on('secureConnect', common.mustCall(function() {
client2.end();
}));
});

View File

@ -34,7 +34,7 @@ export const DEFAULT_MIN_VERSION = "TLSv1.2";
export class CryptoStream {}
export class SecurePair {}
export class Server {}
export const Server = _tls_wrap.Server;
export function createSecurePair() {
notImplemented("tls.createSecurePair");
}

View File

@ -31,12 +31,10 @@ Deno.test("tls.connect makes tls connection", async () => {
const conn = tls.connect({
port: 8443,
host: "localhost",
secureContext: {
ca: rootCaCert,
},
});
conn.write(`GET / HTTP/1.1
Host: localhost
Connection: close
@ -44,9 +42,9 @@ Connection: close
`);
conn.on("data", (chunk) => {
const text = new TextDecoder().decode(chunk);
assertEquals(text, "hello");
});
conn.on("end", () => {
const bodyText = text.split("\r\n\r\n").at(-1)?.trim();
assertEquals(bodyText, "hello");
conn.destroy();
ctl.abort();
});
@ -56,17 +54,21 @@ Connection: close
Deno.test("tls.createServer creates a TLS server", async () => {
const p = deferred();
const server = tls.createServer(
{ hostname: "localhost", key, cert },
{ host: "0.0.0.0", key, cert },
(socket: net.Socket) => {
socket.write("welcome!\n");
socket.setEncoding("utf8");
socket.pipe(socket);
socket.pipe(socket).on("data", (data) => {
if (data.toString().trim() === "goodbye") {
socket.destroy();
}
});
},
);
server.listen(8443, async () => {
server.listen(0, async () => {
const conn = await Deno.connectTls({
hostname: "localhost",
port: 8443,
hostname: "127.0.0.1",
port: server.address().port,
caCerts: [rootCaCert],
});
@ -88,7 +90,7 @@ Deno.test("tls.createServer creates a TLS server", async () => {
text = new TextDecoder().decode(buf);
assertEquals(text.replaceAll("\0", ""), "goodbye\n");
Deno.close(conn.rid);
conn.close();
server.close();
p.resolve();
});