Skip to content

Commit bb703fa

Browse files
committed
[FEAT] [CORE] connect to handshake_first configured NATS servers - specify {tls: {handshakeFirst: true}} connection option. Note that the server must match the configuration option, and will only accept with a matching option.
1 parent 1c061a9 commit bb703fa

File tree

5 files changed

+69
-5
lines changed

5 files changed

+69
-5
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: 2 additions & 1 deletion
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

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: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
ServerInfo,
3434
Transport,
3535
} from "../nats-base-client/internal_mod.ts";
36+
import StartTlsOptions = Deno.StartTlsOptions;
3637

3738
const VERSION = "1.21.0";
3839
const LANG = "nats.deno";
@@ -63,13 +64,29 @@ export class DenoTransport implements Transport {
6364
options: ConnectionOptions,
6465
) {
6566
this.options = options;
67+
68+
const { tls } = this.options;
69+
const { handshakeFirst } = tls || {};
70+
6671
try {
67-
this.conn = await Deno.connect(hp);
72+
if (handshakeFirst === true) {
73+
const opts = await this.loadTlsOptions(hp.hostname);
74+
const ctls = {
75+
caCerts: opts.caCerts,
76+
hostname: hp.hostname,
77+
port: hp.port,
78+
};
79+
this.conn = await Deno.connectTls(ctls);
80+
this.encrypted = true;
81+
// do nothing yet.
82+
} else {
83+
this.conn = await Deno.connect(hp);
84+
}
6885
const info = await this.peekInfo();
6986
checkOptions(info, this.options);
7087
const { tls_required: tlsRequired, tls_available: tlsAvailable } = info;
7188
const desired = tlsAvailable === true && options.tls !== null;
72-
if (tlsRequired || desired) {
89+
if (!handshakeFirst && (tlsRequired || desired)) {
7390
const tlsn = hp.tlsName ? hp.tlsName : hp.hostname;
7491
await this.startTLS(tlsn);
7592
}
@@ -117,7 +134,7 @@ export class DenoTransport implements Transport {
117134
return JSON.parse(m[1]) as ServerInfo;
118135
}
119136

120-
async startTLS(hostname: string): Promise<void> {
137+
async loadTlsOptions(hostname: string): Promise<StartTlsOptions> {
121138
const tls = this.options && this.options.tls
122139
? this.options.tls
123140
: {} as TlsOptions;
@@ -134,7 +151,11 @@ export class DenoTransport implements Transport {
134151
const ca = await Deno.readTextFile(tls.caFile);
135152
sto.caCerts = [ca];
136153
}
154+
return sto;
155+
}
137156

157+
async startTLS(hostname: string): Promise<void> {
158+
const sto = await (this.loadTlsOptions(hostname));
138159
this.conn = await Deno.startTls(
139160
this.conn,
140161
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)