Skip to content

Commit 06d16f8

Browse files
authored
Merge pull request #682 from nats-io/tls-first
[FEAT] `handshake_first` support
2 parents 1c061a9 + 6171b9f commit 06d16f8

File tree

6 files changed

+70
-7
lines changed

6 files changed

+70
-7
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ jobs:
5252
TMPDIR: ${{ runner.temp }}
5353
CI: true
5454
NGS_CI_USER: ${{ secrets.NGS_CI_USER }}
55-
run: deno test --allow-all --unstable --parallel --fail-fast --coverage=./cov
55+
run: |
56+
deno test --allow-all --unstable --parallel --fail-fast --coverage=./cov tests/ jetstream/tests
57+
deno test --allow-all --unstable --parallel --fail-fast --unsafely-ignore-certificate-errors --coverage=./cov unsafe_tests/
5658
5759
- name: Build nats.js
5860
run: deno bundle --unstable src/connect.ts nats.js

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ lint:
88
deno lint --ignore=docs/
99

1010
test: clean
11-
deno test --allow-all --unstable --parallel --reload --quiet --coverage=coverage tests/ jetstream/tests
11+
deno test --allow-all --parallel --reload --quiet --coverage=coverage tests/ jetstream/tests
12+
deno test --allow-all --parallel --reload --quiet --unsafely-ignore-certificate-errors --coverage=coverage unsafe_tests/
1213

1314

1415
testw: clean
@@ -26,4 +27,4 @@ bundle:
2627
deno bundle --log-level info --unstable src/mod.ts ./nats.js
2728

2829
fmt:
29-
deno fmt src/ doc/ bin/ nats-base-client/ examples/ tests/ debug/ jetstream/ jetstream.md README.md services.md
30+
deno fmt src/ doc/ bin/ nats-base-client/ examples/ tests/ debug/ unsafe_tests/ jetstream/ jetstream.md README.md services.md

jetstream/tests/jetstream_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ Deno.test("jetstream - detailed errors", async () => {
12131213
});
12141214

12151215
Deno.test("jetstream - repub on 503", async () => {
1216-
let servers = await NatsServer.setupDataConnCluster(4);
1216+
const servers = await NatsServer.setupDataConnCluster(4);
12171217
const nc = await connect({ port: servers[0].port });
12181218

12191219
const { stream, subj } = await initStream(nc, nuid.next(), {

nats-base-client/core.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,10 @@ export interface ConnectionOptions {
13971397
* the client is requesting to only use connections that are secured by TLS.
13981398
*/
13991399
export interface TlsOptions {
1400+
/**
1401+
* handshakeFirst option requires the server to be configured with `handshakeFirst: true`.
1402+
*/
1403+
handshakeFirst?: boolean;
14001404
certFile?: string;
14011405
cert?: string;
14021406
caFile?: string;

src/deno_transport.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,29 @@ export class DenoTransport implements Transport {
6363
options: ConnectionOptions,
6464
) {
6565
this.options = options;
66+
67+
const { tls } = this.options;
68+
const { handshakeFirst } = tls || {};
69+
6670
try {
67-
this.conn = await Deno.connect(hp);
71+
if (handshakeFirst === true) {
72+
const opts = await this.loadTlsOptions(hp.hostname);
73+
const ctls = {
74+
caCerts: opts.caCerts,
75+
hostname: hp.hostname,
76+
port: hp.port,
77+
};
78+
this.conn = await Deno.connectTls(ctls);
79+
this.encrypted = true;
80+
// do nothing yet.
81+
} else {
82+
this.conn = await Deno.connect(hp);
83+
}
6884
const info = await this.peekInfo();
6985
checkOptions(info, this.options);
7086
const { tls_required: tlsRequired, tls_available: tlsAvailable } = info;
7187
const desired = tlsAvailable === true && options.tls !== null;
72-
if (tlsRequired || desired) {
88+
if (!handshakeFirst && (tlsRequired || desired)) {
7389
const tlsn = hp.tlsName ? hp.tlsName : hp.hostname;
7490
await this.startTLS(tlsn);
7591
}
@@ -117,7 +133,7 @@ export class DenoTransport implements Transport {
117133
return JSON.parse(m[1]) as ServerInfo;
118134
}
119135

120-
async startTLS(hostname: string): Promise<void> {
136+
async loadTlsOptions(hostname: string): Promise<Deno.StartTlsOptions> {
121137
const tls = this.options && this.options.tls
122138
? this.options.tls
123139
: {} as TlsOptions;
@@ -134,7 +150,11 @@ export class DenoTransport implements Transport {
134150
const ca = await Deno.readTextFile(tls.caFile);
135151
sto.caCerts = [ca];
136152
}
153+
return sto;
154+
}
137155

156+
async startTLS(hostname: string): Promise<void> {
157+
const sto = await (this.loadTlsOptions(hostname));
138158
this.conn = await Deno.startTls(
139159
this.conn,
140160
sto,

unsafe_tests/tlsunsafe_test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { resolve } from "https://deno.land/std@0.221.0/path/resolve.ts";
2+
import { join } from "https://deno.land/std@0.221.0/path/join.ts";
3+
import { NatsServer } from "../tests/helpers/launcher.ts";
4+
import { connect } from "../src/connect.ts";
5+
6+
Deno.test("tls-unsafe - handshake first", async () => {
7+
const cwd = Deno.cwd();
8+
const config = {
9+
host: "localhost",
10+
tls: {
11+
handshake_first: true,
12+
cert_file: resolve(join(cwd, "./tests/certs/localhost.crt")),
13+
key_file: resolve(join(cwd, "./tests/certs/localhost.key")),
14+
ca_file: resolve(join(cwd, "./tests/certs/RootCA.crt")),
15+
},
16+
};
17+
18+
const ns = await NatsServer.start(config);
19+
const nc = await connect({
20+
debug: true,
21+
servers: `localhost:${ns.port}`,
22+
tls: {
23+
handshakeFirst: true,
24+
caFile: config.tls.ca_file,
25+
},
26+
});
27+
nc.subscribe("foo", {
28+
callback(_err, msg) {
29+
msg.respond(msg.data);
30+
},
31+
});
32+
33+
await nc.request("foo", "hello");
34+
await nc.close();
35+
await ns.stop();
36+
});

0 commit comments

Comments
 (0)