Skip to content

Commit 7571120

Browse files
authored
Merge pull request #19 from jsonjoy-com/https
TLS/HTTPS support
2 parents d10471c + 9fdc5c9 commit 7571120

File tree

11 files changed

+222
-31
lines changed

11 files changed

+222
-31
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"license": "Apache-2.0",
4141
"scripts": {
4242
"format": "biome format ./src",
43-
"format:write": "biome format --write ./src",
43+
"format:fix": "biome format --write ./src",
4444
"lint": "biome lint ./src",
4545
"lint:fix": "biome lint --apply ./src",
4646
"clean": "rimraf lib typedocs coverage gh-pages yarn-error.log db dist",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Run: npx ts-node src/__demos__/json-crdt-server/main-http1-tls.ts
2+
// curl https://localhost/rx --insecure -d '[1,1,"util.ping"]'
3+
4+
import type * as tls from 'tls';
5+
import * as fs from 'fs';
6+
import {createCaller, createServices} from './routes';
7+
import {RpcServer} from '../../server/http1/RpcServer';
8+
9+
export type JsonJoyDemoRpcCaller = ReturnType<typeof createCaller>['caller'];
10+
11+
const main = async () => {
12+
const secureContext = async (): Promise<tls.SecureContextOptions> => {
13+
return {
14+
key: await fs.promises.readFile(__dirname + '/../../__tests__/certs/server.key'),
15+
cert: await fs.promises.readFile(__dirname + '/../../__tests__/certs/server.crt'),
16+
};
17+
};
18+
19+
const services = await createServices();
20+
const server = await RpcServer.startWithDefaults({
21+
create: {
22+
tls: true,
23+
secureContext,
24+
secureContextRefreshInterval: 1000 * 60 * 60 * 24,
25+
},
26+
port: +(process.env.PORT || 443),
27+
caller: createCaller(services).caller,
28+
logger: console,
29+
});
30+
31+
// tslint:disable-next-line:no-console
32+
console.log(server + '');
33+
};
34+
35+
// tslint:disable-next-line no-console
36+
main().catch(console.error);

src/__demos__/json-crdt-server/main-http1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export type JsonJoyDemoRpcCaller = ReturnType<typeof createCaller>['caller'];
99

1010
const main = async () => {
1111
const services = await createServices();
12-
const server = RpcServer.startWithDefaults({
12+
const server = await RpcServer.startWithDefaults({
1313
port: +(process.env.PORT || 9999),
1414
caller: createCaller(services).caller,
1515
logger: console,

src/__tests__/certs/root.crt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDazCCAlOgAwIBAgIUTCuaouku5UxROTTWDaMZ02A+rMwwDQYJKoZIhvcNAQEL
3+
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMDcwNzM1MDhaFw0yNTEw
5+
MDcwNzM1MDhaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6+
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
7+
AQUAA4IBDwAwggEKAoIBAQCibOXoqQTSAvjVFNOZOt6MT9PK1HqTJjknITMPYsrh
8+
8BZemAAV9pEImeNNBGqScO4oUHX3ZmqcGn6PyTtIWGClXkuVAlghEMNuHqunqRFl
9+
isYaNMsvlmRxFaWVzRq7iN8S+zX0ongtLCUDRexkZmBzM6+aBszifTwMd7oryQhj
10+
9adBROw8yl1yZF33T+a6khQwJ96S5NL/cBbD6aHYH/2DbODN1ru6CGHi0f6b+kUW
11+
1t5xsuc2K+DAWNfmEDQ47EMxS8OYhh2Y/0V/YCIuOIU1tlVL78XjOBmjssPpNFfg
12+
86Uqcfyx0+naQWLF/2r4uUTT3nNhWofM0pXA7DxuMawXAgMBAAGjUzBRMB0GA1Ud
13+
DgQWBBRBA4dUj3VDyFhGSvtIMFkfxMxkOjAfBgNVHSMEGDAWgBRBA4dUj3VDyFhG
14+
SvtIMFkfxMxkOjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBi
15+
UTc+mRjoSKjpxYgoEFF6MDm24IrZ9b0NSFNHrM9hbbbErJgQ3UJkUAjXweRxvWPw
16+
gL8HLGLDjsUg/h4D33xndmoXPvmQAuiBFaujWqOeZ7mcwbLNVkDNZzgdo8ggfXkn
17+
e64u37aSoUV+XdyeyJyRBHpVfdTPeptN/KhdijjL0uWiw48A7sDZsgz0SZKSxdF3
18+
TVQA2W1dGJ0yAEqnbIc3f2HbRg6PXs2jyQ0pdWjQlaARJ3KV433V2T0ecKXQaXoL
19+
B8cvXrfn4dEkHd4tBZqB5Z/bVxj14g5jtq5f/FWupZwWCvP28vDe0ZJw/5/7R10R
20+
1S3XB1fJh48m0c7k9gn3
21+
-----END CERTIFICATE-----

src/__tests__/certs/root.key

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCibOXoqQTSAvjV
3+
FNOZOt6MT9PK1HqTJjknITMPYsrh8BZemAAV9pEImeNNBGqScO4oUHX3ZmqcGn6P
4+
yTtIWGClXkuVAlghEMNuHqunqRFlisYaNMsvlmRxFaWVzRq7iN8S+zX0ongtLCUD
5+
RexkZmBzM6+aBszifTwMd7oryQhj9adBROw8yl1yZF33T+a6khQwJ96S5NL/cBbD
6+
6aHYH/2DbODN1ru6CGHi0f6b+kUW1t5xsuc2K+DAWNfmEDQ47EMxS8OYhh2Y/0V/
7+
YCIuOIU1tlVL78XjOBmjssPpNFfg86Uqcfyx0+naQWLF/2r4uUTT3nNhWofM0pXA
8+
7DxuMawXAgMBAAECggEAJwQOk/0prcLN/+1BSND1zXGNd+7jRL6NQwN8DumVv4Ea
9+
9nz/pEb2nsDMc18otGWRJ7jwJU4CNN4+YY6egWnNSVvlvvTxs3uh3i1a4WrAxYn4
10+
vSnKVvOCzBE9lcbPcZXWs+oJE2sFgCBXAbrFpnZbG8EiINcaVxtrFbmazFK9g7kI
11+
Cvn8fzfsl2hSodusj9HuNNjfZL1CewHrF/xtuLp50wTvTpS2IZVqfhIpuuf1lmHf
12+
tArJIbW3Rp3VUUtlEc6OEFa8xMVoJF1zNSBgIeUq00UjEtS3nTTZprt29ggigI2d
13+
GfJ/89vXRIaorGuGOI6of8CgpDKlA0oYXy94sh/v9QKBgQDO6LRWGR3jTePSEXZR
14+
E+ph74zLHOpfrDed7LYeOlV7zBciN8D1q9KpOQVMY/7Lenok5f2svJeO8hxGeM9J
15+
F13xzmITQppxoq3qoMOQm4FtGe+MsTe1nXtUGldUbMQwwFL5GqxYjCUI9sDXGEox
16+
zBawUa/KDuD+p1nQn9sG+h/5OwKBgQDI9lXfvqIEC22PboyN3Jp5n+PVy2xJera8
17+
BPHvdiRLfdZitRRfJ5wg0/B1euVsnLRPGRI321r7IidELGX/VT3jvEIHYFVXfH3e
18+
xnQWyvOTdnXmgIZYIlgnk7ryDSpwNnDaHzX8ozoVtXl8G08CD+T74KcSr0R+pof0
19+
ssAUv+EK1QKBgAQgWfBZoeH1nLSEyqJFTmhTmbA3TGlKCvXoUZ16tle4s0FocT21
20+
Bod/bp6eY+d08tiniY6XWEJui6fQIvonMCVxYz1VF7VqdCN4v02z/DnLyZ45ro29
21+
rUb5G4LAhI0gWMdFA+jkKpzqJuBjSJ+DnXQ4vNO/xjbt6XmipoCWHmsfAoGAUa+H
22+
omXrlzdJ9mZaLYPBKrTqOEnynz+JLY3ZBZwBDsp8rSyrti30kYd0k1w8C1T7Gbe4
23+
Jwo7xh7Q1S4y24G7oWkxcawfpGsPAtGp+GXQcl1ReTs+4G49ZQDwmVjuqiQG5TKQ
24+
kDuM7awRUHgNOmpZimR7pOWnMs/gLX/HAegowm0CgYBZKUy7hNNY9bjbi8AmADWP
25+
g0roJZYU+12EvrR1AShVx6oE5Oq/w3WnG1qyFaoaIo36kkGB5yZDQkySN6UV3GF/
26+
sHaWtGVVcYnTFiDkeH4BAxKhLg/0q+ipfVT18dlPec5WhVhgHtldFeCP0j7UFQEx
27+
Dn97qAEU6vqvMz8vUBXTxA==
28+
-----END PRIVATE KEY-----

src/__tests__/certs/root.srl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2AAEBC5B9C0D89E6BF42BF00A11B7178A5BDD49A

src/__tests__/certs/server.crt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDWjCCAkKgAwIBAgIUKq68W5wNiea/Qr8AoRtxeKW91JowDQYJKoZIhvcNAQEL
3+
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
4+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMDcwOTA2MjNaFw0yNTEw
5+
MDcwOTA2MjNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
6+
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
7+
AQUAA4IBDwAwggEKAoIBAQDHeHPg8Z+3WPdsoV3Io7ZxEAbAiYPm30vq9I6u6uHY
8+
c2BK/sYAEolQ6a1KMGXeElEtav/msJ1sAr5AX62QiMIie1CV0HN8bUrYeYxM3gdn
9+
f18qW4q1Cxy3o+lZ42QvwJksC0JbsvD7Eg5SW/pD89hxD1ovREnxbNNZkPkaxCcg
10+
YzruILGkCSWpBjYiXeebjxZTam84fauUXLlzjp7ox2xhBLg5fxxd9aPahc2szLeY
11+
7v4pk3wZJ8EU3BJpgkOQrlyLQmZ31/dWDAHxqRteFqt6wGLvBYBwxKvHcWyxoxhI
12+
5AU6c5IWiUn0Sd66dy31X+konEZSPaUchyGsqTTTpkfjAgMBAAGjQjBAMB0GA1Ud
13+
DgQWBBT4zgQm2Katn77dYvHsiT4b/9v8bTAfBgNVHSMEGDAWgBRBA4dUj3VDyFhG
14+
SvtIMFkfxMxkOjANBgkqhkiG9w0BAQsFAAOCAQEAia33i3C2yRjh228e3SOOiECn
15+
kAC7aiZ9Qry/lO241XCz9T/SayRuisq5L1B0vBIKMnuqJw6DX+hrnHPJkx7H5N5a
16+
ISwlCCOjcurIDdI2tZZrYu0CLpAhSpY0/hFWswnNKefOWgmDRpxw4iBLpAAeAv5z
17+
aohmi98JdthOQHWvPvu0APz/r7Nb0GpDXjyU2daBnxkiEvBOxXJ7KiFt336haOrn
18+
EJ3Fbba335rfI9CFqCERHjE/SaJGxrL4z8FRx86HdKbl39ILGr73TyySOh0Tp/iG
19+
FXzN2POaKzFdB0ezHZsWyh5KeW7AlJaw5SvHLFljV+r1vRR9sX4O+tj04u6V4Q==
20+
-----END CERTIFICATE-----

src/__tests__/certs/server.csr

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN CERTIFICATE REQUEST-----
2+
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
3+
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
4+
AQEBBQADggEPADCCAQoCggEBAMd4c+Dxn7dY92yhXcijtnEQBsCJg+bfS+r0jq7q
5+
4dhzYEr+xgASiVDprUowZd4SUS1q/+awnWwCvkBfrZCIwiJ7UJXQc3xtSth5jEze
6+
B2d/XypbirULHLej6VnjZC/AmSwLQluy8PsSDlJb+kPz2HEPWi9ESfFs01mQ+RrE
7+
JyBjOu4gsaQJJakGNiJd55uPFlNqbzh9q5RcuXOOnujHbGEEuDl/HF31o9qFzazM
8+
t5ju/imTfBknwRTcEmmCQ5CuXItCZnfX91YMAfGpG14Wq3rAYu8FgHDEq8dxbLGj
9+
GEjkBTpzkhaJSfRJ3rp3LfVf6SicRlI9pRyHIaypNNOmR+MCAwEAAaAAMA0GCSqG
10+
SIb3DQEBCwUAA4IBAQBzZYKoSCgIvpJTF9/vgkdJDpWnVROf5xbUCXym8j80ouOm
11+
Wi8sIgdEqofwlUguPvTD2WLKY40tBHTOEtTtnFYXhHOKAQLduHTrVHzZ3MddcLbI
12+
+9FbDmQKnJtGGUQrzUKfRKPcEwZiXxn3IclPbR/bvZP5F+7brMNOTN/AAfBBAByw
13+
RYhwOiKiMlodDWFHLBdllY5z5o/nlIXMuPrWclUMSZjoERbM3niSF3fhw1j9m4Tl
14+
XJnQq0i7n/7KQSRGweckaP3rJu5yn8SmkxmNAo9Fj0H51tpYEdc2K256QVKTGSr2
15+
bNCcr60ToRiLUL4vokrCbUyIqAPahVwnWg0Kkux1
16+
-----END CERTIFICATE REQUEST-----

src/__tests__/certs/server.key

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDHeHPg8Z+3WPds
3+
oV3Io7ZxEAbAiYPm30vq9I6u6uHYc2BK/sYAEolQ6a1KMGXeElEtav/msJ1sAr5A
4+
X62QiMIie1CV0HN8bUrYeYxM3gdnf18qW4q1Cxy3o+lZ42QvwJksC0JbsvD7Eg5S
5+
W/pD89hxD1ovREnxbNNZkPkaxCcgYzruILGkCSWpBjYiXeebjxZTam84fauUXLlz
6+
jp7ox2xhBLg5fxxd9aPahc2szLeY7v4pk3wZJ8EU3BJpgkOQrlyLQmZ31/dWDAHx
7+
qRteFqt6wGLvBYBwxKvHcWyxoxhI5AU6c5IWiUn0Sd66dy31X+konEZSPaUchyGs
8+
qTTTpkfjAgMBAAECggEAHB1STo8ai7f1Q8aTa+SwoctNpanxlphm4Gpw3p705H0P
9+
7PIaS/H7kGp8m3DVOCbiceGGHmif/5R8EUxgWndUJD0M9Ni+dk1cl8S7WC2ROJlq
10+
JekPf14Iwaok3p+0xCBEK+zjAP692tLG2afkzzAZk9yYlwHr3s86aNeMrM+fPiqj
11+
0ySjKj+VIgDO+6pItaUdHhgfX+57mzW6FIyiuF5j4fC2w/BFWj8QRXoVul0NNLID
12+
kfbz0bE3VyFIQcqx68SwD9CoHwIgLYp5uWr57elf9Fd0eFBDSkJglOFCGuhTL/G+
13+
7nIjLpupuZQy+t9UEH81zM3MPR9OKjLXw9oXtw0Y0QKBgQDxBKATjnJhgAC+iEQ0
14+
SIySrYa86vo+HxJPbxmv7zKgMTWkfkoUELA3ZrAsR3pyf8a3GNfjwk7iuUEexO4M
15+
hMqR+7rMY4ORHcHL5OQNYVQF35AOxNS5VKwFt/+Q307pHPQ34Wh9VZ/41Zt/+RFd
16+
JYFPpupb+RLcx8c9ddwXl0wYEQKBgQDT3qv+1Th7QX/J2oTjajPDo4bu/ZgrqNRo
17+
mKlL5ngji99fNNt4hT4AGS5S5s2h/5gdfqkF+0dYbdCPAGk6qNdUSAQ+SSCjVFwr
18+
+WDOwYzHaoLtPIDMqBW+O9jkFvSgwVAnW6WBWDUEnOg/3IkAISSQoOOemTyAnIUL
19+
z+lvqa40swKBgQDiFzqq3ceCmvcXxPBmM2BbABkTA0J4H+GnTktEdRiCmWb+xdFr
20+
/TOw5M2C3BKLcj3Q6Kcs6svhd3MVEBtW9wKn6wKSVQ/Ig6eWQ0ODIbgWQl/62r3K
21+
lRlBzBcbqb92gki+Wt8QI9CLNqZGaDjXriUduTDD0mTVYzsN9o/eOXmSYQKBgQCo
22+
qpMIOxxM21btDf5OwQRWkf9gkRgsYao/XpEgMGih+78mnwC9UG2MTH+ZVc6MUdr6
23+
WBQdA+7HUhz/Std68GED4pUmNLc773O1OkE8N89oDb4POORciM9Oc3x2EGRM+bhi
24+
rM30S5Fhi7xE4r9aEAh47uxmHR2SUYiFX845q75YiwKBgQDOhMRsDY0IplKj1DzI
25+
DK2AcQzhEpXl3wTbcxs48FJs1pBwYPxfgcNEqaHS3nFqwGufeOY7txzfYD758rSO
26+
f+497Z0gLZ6gqdleUNVGqaRYS5oqEhLIV6/k9zkJiBrlh1wztiVSpjZ8on6YeKp7
27+
Uy/eYp2ikaeFHMW1VOBx0G6qeg==
28+
-----END PRIVATE KEY-----

src/server/http1/Http1Server.ts

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import * as http from 'http';
2+
import * as https from 'https';
3+
import type * as tls from 'tls';
24
import type * as net from 'net';
35
import {Writer} from '@jsonjoy.com/util/lib/buffers/Writer';
46
import {Codecs} from '@jsonjoy.com/json-pack/lib/codecs/Codecs';
@@ -64,13 +66,55 @@ export interface Http1ServerOpts {
6466
writer?: Writer;
6567
}
6668

69+
export type Http1CreateServerOpts = Http1CreateHttpServerOpts | Http1CreateHttpsServerOpts;
70+
71+
export interface Http1CreateHttpServerOpts {
72+
tls?: false;
73+
conf?: http.ServerOptions;
74+
}
75+
76+
export interface Http1CreateHttpsServerOpts {
77+
tls: true;
78+
conf?: https.ServerOptions;
79+
secureContext?: () => Promise<tls.SecureContextOptions>;
80+
81+
/**
82+
* If specified, and the `secureContext` is also specified, will be used to
83+
* refresh the secure context every `secureContextRefreshInterval` milliseconds.
84+
*/
85+
secureContextRefreshInterval?: number;
86+
}
87+
6788
export class Http1Server implements Printable {
68-
public static start(opts: http.ServerOptions = {}, port = 8000): Http1Server {
69-
const rawServer = http.createServer(opts);
70-
rawServer.listen(port);
71-
const server = new Http1Server({server: rawServer});
72-
return server;
73-
}
89+
public static create = async (opts: Http1CreateServerOpts = {}): Promise<http.Server | https.Server> => {
90+
if (opts.tls) {
91+
const {secureContext, secureContextRefreshInterval} = opts;
92+
const server = https.createServer({
93+
...(secureContext ? await secureContext() : {}),
94+
...opts.conf,
95+
});
96+
if (secureContext && secureContextRefreshInterval) {
97+
const timer = setInterval(() => {
98+
try {
99+
secureContext()
100+
.then((context) => {
101+
server.setSecureContext(context);
102+
})
103+
.catch((error) => {
104+
console.error('Failed to update secure context:', error);
105+
});
106+
} catch (error) {
107+
console.error('Failed to update secure context:', error);
108+
}
109+
}, secureContextRefreshInterval);
110+
server.once('close', () => {
111+
clearInterval(timer);
112+
});
113+
}
114+
return server;
115+
}
116+
return http.createServer(opts.conf || {});
117+
};
74118

75119
public readonly codecs: RpcCodecs;
76120
public readonly server: http.Server;
@@ -82,7 +126,7 @@ export class Http1Server implements Printable {
82126
this.wsEncoder = new WsFrameEncoder(writer);
83127
}
84128

85-
public start(): void {
129+
public async start(): Promise<void> {
86130
const server = this.server;
87131
this.httpMatcher = this.httpRouter.compile();
88132
this.wsMatcher = this.wsRouter.compile();
@@ -93,6 +137,11 @@ export class Http1Server implements Printable {
93137
});
94138
}
95139

140+
public async stop(): Promise<void> {
141+
const server = this.server;
142+
server.removeAllListeners();
143+
}
144+
96145
// ------------------------------------------------------------- HTTP routing
97146

98147
public onnotfound: Http1NotFoundHandler = (res) => {

0 commit comments

Comments
 (0)