Skip to content
File

Blob: src/workerd/api/tests/starttls-nodejs-test.js

javascript171 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5import { connect } from 'cloudflare:sockets';
6import { ok, strict as assert } from 'node:assert';
7import { connect as tlsConnect } from 'node:tls';
8import { connect as netConnect } from 'node:net';
9 
10export const checkPortsSetCorrectly = {
11 test(ctrl, env, ctx) {
12 const keys = ['STARTTLS_CA_PORT'];
13 for (const key of keys) {
14 assert.strictEqual(typeof env[key], 'string');
15 ok(env[key].length > 0);
16 }
17 },
18};
19 
20export const startTlsCATest = {
21 async test(ctrl, env, ctx) {
22 const opts = {
23 servername: 'localhost',
24 port: env.STARTTLS_CA_PORT,
25 rejectUnauthorized: true,
26 };
27 
28 const socket = netConnect(opts.port);
29 
30 // Wait for server's greeting then respond
31 socket.once('data', (data) => {
32 const greeting = data.toString().trim();
33 console.log('startTlsCATest: Received greeting:', greeting);
34 
35 if (greeting === 'HELLO') {
36 console.log('startTlsCATest: Sending HELLO_BACK');
37 socket.write('HELLO_BACK\n');
38 
39 // Wait for START_TLS signal
40 socket.once('data', (data) => {
41 const signal = data.toString().trim();
42 console.log('startTlsCATest: Received signal:', signal);
43 
44 if (signal === 'START_TLS') {
45 console.log('startTlsCATest: Received START_TLS, upgrading to TLS');
46 
47 // Upgrade to TLS - pass socket in the options
48 const tlsSocket = tlsConnect(
49 {
50 ...opts,
51 socket: socket,
52 },
53 function () {
54 console.log(
55 'startTlsCATest: TLS connection established successfully'
56 );
57 
58 // Send ping message
59 console.log('startTlsCATest: Sending ping message');
60 this.write('ping\n', (err) => {
61 if (err) {
62 console.log('startTlsCATest: Error writing ping:', err);
63 } else {
64 console.log('startTlsCATest: Ping sent successfully');
65 }
66 });
67 
68 // Wait for pong response
69 this.once('data', (data) => {
70 const response = data.toString().trim();
71 console.log('startTlsCATest: Received response:', response);
72 
73 // Assert response is 'pong'
74 assert.strictEqual(
75 response,
76 'pong',
77 'Expected pong response'
78 );
79 
80 this.end();
81 });
82 }
83 );
84 
85 tlsSocket.on('error', (err) => {
86 console.log('startTlsCATest: TLS connection error:', err.message);
87 throw err;
88 });
89 }
90 });
91 }
92 });
93 
94 socket.on('error', (err) => {
95 console.log('startTlsCATest: Socket connection error:', err.message);
96 throw err;
97 });
98 },
99};
100 
101export const startTlsCloudflareTest = {
102 async test(ctrl, env, ctx) {
103 // Create a Cloudflare socket connection with STARTTLS
104 const socket = connect(`localhost:${env.STARTTLS_CA_PORT}`, {
105 secureTransport: 'starttls',
106 });
107 
108 const writer = socket.writable.getWriter();
109 const reader = socket.readable.getReader();
110 
111 try {
112 // Read HELLO greeting
113 const { value: greeting } = await reader.read();
114 const greetingText = new TextDecoder().decode(greeting).trim();
115 console.log('startTlsCfTest: Received greeting:', greetingText);
116 
117 if (greetingText === 'HELLO') {
118 console.log('startTlsCfTest: Sending HELLO_BACK');
119 await writer.write(new TextEncoder().encode('HELLO_BACK\n'));
120 
121 // Read START_TLS signal
122 const { value: signal } = await reader.read();
123 const signalText = new TextDecoder().decode(signal).trim();
124 console.log('startTlsCfTest: Received signal:', signalText);
125 
126 if (signalText === 'START_TLS') {
127 console.log('startTlsCfTest: Received START_TLS, upgrading to TLS');
128 
129 // Release the reader and writer before upgrading
130 reader.releaseLock();
131 writer.releaseLock();
132 
133 // Upgrade to TLS using Cloudflare socket's startTls
134 console.log('startTlsCfTest: About to start TLS');
135 const tlsSocket = socket.startTls();
136 console.log('startTlsCfTest: Started TLS');
137 
138 await tlsSocket.opened;
139 console.log(
140 'startTlsCfTest: TLS connection established successfully'
141 );
142 
143 // Get new writer and reader for TLS socket
144 const tlsWriter = tlsSocket.writable.getWriter();
145 const tlsReader = tlsSocket.readable.getReader();
146 
147 // Send ping message
148 console.log('startTlsCfTest: Sending ping message');
149 await tlsWriter.write(new TextEncoder().encode('ping\n'));
150 
151 // Read pong response
152 const { value: response } = await tlsReader.read();
153 const responseText = new TextDecoder().decode(response).trim();
154 console.log('startTlsCfTest: Received response:', responseText);
155 
156 // Assert response is 'pong'
157 assert.strictEqual(responseText, 'pong', 'Expected pong response');
158 
159 // Close the socket
160 tlsReader.releaseLock();
161 tlsWriter.releaseLock();
162 await tlsSocket.close();
163 }
164 }
165 } catch (err) {
166 console.log('startTlsCfTest: Error:', err.message);
167 throw err;
168 }
169 },
170};