socket-function 0.8.0 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SocketFunction.ts +2 -0
- package/SocketFunctionTypes.ts +25 -2
- package/hot/HotReloadController.ts +65 -0
- package/package.json +2 -2
- package/spec.txt +0 -1
- package/src/CallFactory.ts +11 -6
- package/src/callHTTPHandler.ts +4 -2
- package/src/callManager.ts +2 -3
- package/src/nodeAuthentication.ts +59 -70
- package/src/webSocketServer.ts +12 -1
package/SocketFunction.ts
CHANGED
package/SocketFunctionTypes.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import debugbreak from "debugbreak";
|
|
2
|
+
import * as tls from "tls";
|
|
3
|
+
|
|
1
4
|
export const socket = Symbol("socket");
|
|
2
5
|
|
|
3
6
|
export type SocketExposedInterface = {
|
|
@@ -30,13 +33,13 @@ export interface SocketFunctionHook<ExposedType extends SocketExposedInterface =
|
|
|
30
33
|
export type HookContext<ExposedType extends SocketExposedInterface = SocketExposedInterface, CallContext extends CallContextType = CallContextType> = {
|
|
31
34
|
call: CallType;
|
|
32
35
|
context: SocketRegistered["context"];
|
|
33
|
-
// If the result is overriden, we continue evaluating hooks
|
|
36
|
+
// If the result is overriden, we continue evaluating hooks BUT NOT perform the final call
|
|
34
37
|
overrideResult?: unknown;
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
export type ClientHookContext<ExposedType extends SocketExposedInterface = SocketExposedInterface, CallContext extends CallContextType = CallContextType> = {
|
|
38
41
|
call: CallType;
|
|
39
|
-
// If the result is overriden, we continue evaluating hooks
|
|
42
|
+
// If the result is overriden, we continue evaluating hooks BUT NOT perform the final call
|
|
40
43
|
overrideResult?: unknown;
|
|
41
44
|
};
|
|
42
45
|
export interface SocketFunctionClientHook<ExposedType extends SocketExposedInterface = SocketExposedInterface, CallContext extends CallContextType = CallContextType> {
|
|
@@ -70,8 +73,28 @@ export type CallerContext = {
|
|
|
70
73
|
// The location of the server. It helps if it is told, due to the fact that one server
|
|
71
74
|
// can serve multiple domains.
|
|
72
75
|
serverLocation: NetworkLocation;
|
|
76
|
+
|
|
77
|
+
// NOTE: Only set in NodeJS, as clientside we are not given access to the certificate information.
|
|
78
|
+
// TODO: Limit this type to only have the information we need, possible in a slightly different format.
|
|
79
|
+
certInfo: tls.DetailedPeerCertificate | undefined;
|
|
80
|
+
|
|
81
|
+
// TODO: Add callerBrowserAuthIP, which will allow "Proxy-IP" (or whatever cloudflare uses? It has to be a
|
|
82
|
+
// header which the browser is restricted from sending), to override this, allowing the browser to use
|
|
83
|
+
// proxies.
|
|
84
|
+
// - We have to also ONLY accept this from certain trusted servers, as otherwise it is too easy to spoof.
|
|
85
|
+
//callerBrowserAuthIP: string;
|
|
73
86
|
};
|
|
74
87
|
|
|
88
|
+
export function setCertInfo(socket: tls.TLSSocket | undefined, context: CallerContext) {
|
|
89
|
+
if (!socket) return;
|
|
90
|
+
let cert = socket.getPeerCertificate(true);
|
|
91
|
+
/** Check for a property, because "If the peer does not provide a certificate, an empty object will be
|
|
92
|
+
returned. If the socket has been destroyed, `null` will be returned." */
|
|
93
|
+
if (cert?.issuer) {
|
|
94
|
+
context.certInfo = cert;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
75
98
|
// IMPORTANT! Nodes at the same network location may vary, so you cannot store NetworkLocation
|
|
76
99
|
// in a list of allowed users, otherwise they can be impersonated!
|
|
77
100
|
export interface NetworkLocation {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SocketFunction } from "../SocketFunction";
|
|
2
|
+
import { cache, lazy } from "../src/caching";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
|
|
5
|
+
/** Hot reloads server and client files, just trigger a refresh clientside,
|
|
6
|
+
* while triggering per file re-evaluation and export updates serverside.
|
|
7
|
+
* - Requires HotReloadController to be exposed.
|
|
8
|
+
*/
|
|
9
|
+
export function watchFilesAndTriggerHotReloading() {
|
|
10
|
+
setInterval(() => {
|
|
11
|
+
for (let module of Object.values(require.cache)) {
|
|
12
|
+
if (!module) continue;
|
|
13
|
+
hotReloadModule(module);
|
|
14
|
+
}
|
|
15
|
+
}, 5000);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const hotReloadModule = cache((module: NodeJS.Module) => {
|
|
20
|
+
if (!module.updateContents) return;
|
|
21
|
+
fs.watchFile(module.filename, { persistent: false, interval: 1000 }, (curr, prev) => {
|
|
22
|
+
if (curr.mtime.getTime() === prev.mtime.getTime()) return;
|
|
23
|
+
console.log(`Hot reloading due to change: ${module.filename}`);
|
|
24
|
+
module.updateContents?.();
|
|
25
|
+
triggerClientSideReload();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
let reloadTriggering = false;
|
|
29
|
+
let clientWatcherNodes = new Set<string>();
|
|
30
|
+
function triggerClientSideReload() {
|
|
31
|
+
if (reloadTriggering) return;
|
|
32
|
+
reloadTriggering = true;
|
|
33
|
+
setTimeout(async () => {
|
|
34
|
+
reloadTriggering = false;
|
|
35
|
+
for (let clientNodeId of clientWatcherNodes) {
|
|
36
|
+
console.log(`Notifying client of hot reload: ${clientNodeId}`);
|
|
37
|
+
HotReloadController.nodes[clientNodeId].fileUpdated().catch(() => {
|
|
38
|
+
console.log(`Removing erroring client: ${clientNodeId}`);
|
|
39
|
+
clientWatcherNodes.delete(clientNodeId);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}, 300);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class HotReloadControllerBase {
|
|
46
|
+
async watchFiles() {
|
|
47
|
+
let callerId = HotReloadController.context.caller?.nodeId;
|
|
48
|
+
if (!callerId) {
|
|
49
|
+
throw new Error("No nodeId?");
|
|
50
|
+
}
|
|
51
|
+
clientWatcherNodes.add(callerId);
|
|
52
|
+
}
|
|
53
|
+
async fileUpdated() {
|
|
54
|
+
document.location.reload();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const HotReloadController = SocketFunction.register(
|
|
59
|
+
"HotReloadController-032b2250-3aac-4187-8c95-75412742b8f5",
|
|
60
|
+
new HotReloadControllerBase(),
|
|
61
|
+
{
|
|
62
|
+
watchFiles: {},
|
|
63
|
+
fileUpdated: {}
|
|
64
|
+
}
|
|
65
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "socket-function",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"@types/ws": "^8.5.3",
|
|
10
10
|
"cookie": "^0.5.0",
|
|
11
11
|
"debugbreak": "^0.6.5",
|
|
12
|
-
"typenode": "
|
|
12
|
+
"typenode": "^0.5.6",
|
|
13
13
|
"ws": "^8.8.0"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
package/spec.txt
CHANGED
package/src/CallFactory.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { CallerContext, CallType, NetworkLocation } from "../SocketFunctionTypes";
|
|
1
|
+
import { CallerContext, CallType, NetworkLocation, setCertInfo } from "../SocketFunctionTypes";
|
|
2
2
|
import * as ws from "ws";
|
|
3
3
|
import type * as net from "net";
|
|
4
4
|
import { performLocalCall } from "./callManager";
|
|
5
5
|
import { convertErrorStackToError, formatNumberSuffixed, isNode } from "./misc";
|
|
6
|
-
import {
|
|
6
|
+
import { createWebsocketFactory, getNodeId, getTLSSocket } from "./nodeAuthentication";
|
|
7
7
|
import debugbreak from "debugbreak";
|
|
8
8
|
import http from "http";
|
|
9
9
|
import { SocketFunction } from "../SocketFunction";
|
|
10
10
|
import { gzip } from "zlib";
|
|
11
|
+
import * as tls from "tls";
|
|
11
12
|
|
|
12
13
|
const retryInterval = 2000;
|
|
13
14
|
|
|
@@ -80,6 +81,8 @@ export async function callFactoryFromWS(
|
|
|
80
81
|
|
|
81
82
|
export interface SenderInterface {
|
|
82
83
|
nodeId?: string;
|
|
84
|
+
// Only set AFTER "open" (if set at all, as in the browser we don't have access to the socket).
|
|
85
|
+
socket?: tls.TLSSocket;
|
|
83
86
|
|
|
84
87
|
send(data: string | Buffer): void;
|
|
85
88
|
|
|
@@ -107,6 +110,8 @@ async function createCallFactory(
|
|
|
107
110
|
niceConnectionName += `(${fromPort})`;
|
|
108
111
|
}
|
|
109
112
|
|
|
113
|
+
const createWebsocket = createWebsocketFactory();
|
|
114
|
+
|
|
110
115
|
let retriesEnabled = location.listeningPorts.length > 0;
|
|
111
116
|
|
|
112
117
|
let lastReceivedSeqNum = 0;
|
|
@@ -127,7 +132,7 @@ async function createCallFactory(
|
|
|
127
132
|
let nextSeqNum = Math.random();
|
|
128
133
|
|
|
129
134
|
const pendingNodeId = "PENDING";
|
|
130
|
-
let callerContext: CallerContext = { location, nodeId: pendingNodeId, serverLocation, fromPort };
|
|
135
|
+
let callerContext: CallerContext = { location, nodeId: pendingNodeId, serverLocation, fromPort, certInfo: undefined };
|
|
131
136
|
let webSocket!: SenderInterface;
|
|
132
137
|
if (!webSocketBase) {
|
|
133
138
|
await tryToReconnect();
|
|
@@ -258,8 +263,8 @@ async function createCallFactory(
|
|
|
258
263
|
return;
|
|
259
264
|
}
|
|
260
265
|
|
|
261
|
-
console.error(`Connection retry to ${location.address}:${port} failed, retrying in ${retryInterval}ms`);
|
|
262
266
|
reconnectAttempts++;
|
|
267
|
+
console.error(`Connection retry to ${location.address}:${port} failed (attempt ${reconnectAttempts}), retrying in ${retryInterval}ms, error: ${JSON.stringify(connectError)}`);
|
|
263
268
|
await new Promise(resolve => setTimeout(resolve, retryInterval));
|
|
264
269
|
}
|
|
265
270
|
})();
|
|
@@ -278,6 +283,8 @@ async function createCallFactory(
|
|
|
278
283
|
});
|
|
279
284
|
|
|
280
285
|
webSocket.addEventListener("message", onMessage);
|
|
286
|
+
|
|
287
|
+
setCertInfo(webSocket.socket || (webSocket as any)._socket, callerContext);
|
|
281
288
|
}
|
|
282
289
|
|
|
283
290
|
|
|
@@ -361,8 +368,6 @@ async function createCallFactory(
|
|
|
361
368
|
}
|
|
362
369
|
return;
|
|
363
370
|
}
|
|
364
|
-
debugbreak(1);
|
|
365
|
-
debugger;
|
|
366
371
|
throw new Error(`Unhandled data type ${typeof message}`);
|
|
367
372
|
} catch (e: any) {
|
|
368
373
|
console.error(e.stack);
|
package/src/callHTTPHandler.ts
CHANGED
|
@@ -2,7 +2,7 @@ import https from "https";
|
|
|
2
2
|
import http from "http";
|
|
3
3
|
import net from "net";
|
|
4
4
|
import tls from "tls";
|
|
5
|
-
import { CallerContext, CallType, NetworkLocation } from "../SocketFunctionTypes";
|
|
5
|
+
import { CallerContext, CallType, NetworkLocation, setCertInfo } from "../SocketFunctionTypes";
|
|
6
6
|
import { performLocalCall } from "./callManager";
|
|
7
7
|
import { getNodeIdRaw } from "./nodeAuthentication";
|
|
8
8
|
import debugbreak from "debugbreak";
|
|
@@ -111,7 +111,9 @@ export async function httpCallHandler(request: http.IncomingMessage, response: h
|
|
|
111
111
|
listeningPorts: [],
|
|
112
112
|
},
|
|
113
113
|
serverLocation: getServerLocationFromRequest(request),
|
|
114
|
+
certInfo: undefined,
|
|
114
115
|
};
|
|
116
|
+
setCertInfo(socket, caller);
|
|
115
117
|
|
|
116
118
|
let classGuid = urlObj.searchParams.get("classGuid");
|
|
117
119
|
let functionName = urlObj.searchParams.get("functionName");
|
|
@@ -173,8 +175,8 @@ export async function httpCallHandler(request: http.IncomingMessage, response: h
|
|
|
173
175
|
|
|
174
176
|
// NOTE: Our ETag caching is only to reduce data sent on the wire, we evaluate the calls
|
|
175
177
|
// every time (so it is strictly a wire cache, not computation cache)
|
|
176
|
-
response.setHeader("cache-control", "private, s-maxage=0, max-age=0, must-revalidate");
|
|
177
178
|
if (SocketFunction.httpETagCache) {
|
|
179
|
+
response.setHeader("cache-control", "private, s-maxage=0, max-age=0, must-revalidate");
|
|
178
180
|
let hash = sha256Hash(resultBuffer);
|
|
179
181
|
response.setHeader("ETag", hash);
|
|
180
182
|
if (request.headers["if-none-match"] === hash) {
|
package/src/callManager.ts
CHANGED
|
@@ -30,8 +30,7 @@ export async function performLocalCall(
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
let controller = classDef.controller;
|
|
33
|
-
let
|
|
34
|
-
let functionShape = shape[call.functionName];
|
|
33
|
+
let functionShape = classDef.shape[call.functionName];
|
|
35
34
|
if (!functionShape) {
|
|
36
35
|
throw new Error(`Function ${call.functionName} not exposed`);
|
|
37
36
|
}
|
|
@@ -41,7 +40,7 @@ export async function performLocalCall(
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
let curContext: CallContextType = {};
|
|
44
|
-
let serverContext = await runServerHooks(call, { caller, curContext },
|
|
43
|
+
let serverContext = await runServerHooks(call, { caller, curContext }, functionShape);
|
|
45
44
|
if ("overrideResult" in serverContext) {
|
|
46
45
|
return serverContext.overrideResult;
|
|
47
46
|
}
|
|
@@ -11,14 +11,20 @@ import crypto from "crypto";
|
|
|
11
11
|
import { isNode, sha256Hash } from "./misc";
|
|
12
12
|
import { getArgs } from "./args";
|
|
13
13
|
import { SenderInterface } from "./CallFactory";
|
|
14
|
+
import { SocketFunction } from "../SocketFunction";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
let certKeyPairOverride: { key: Buffer; cert: Buffer } | undefined;
|
|
17
|
+
export function getCertKeyPair(): { key: Buffer; cert: Buffer } {
|
|
18
|
+
if (certKeyPairOverride) return certKeyPairOverride;
|
|
19
|
+
return getCertKeyPairBase();
|
|
20
|
+
}
|
|
21
|
+
const getCertKeyPairBase = lazy((): { key: Buffer; cert: Buffer } => {
|
|
16
22
|
// TODO: Also get this working clientside...
|
|
17
|
-
// -
|
|
23
|
+
// - Use https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
|
|
24
|
+
// - We might need node-forge for the Certificate Signing Request and x509 stuff
|
|
25
|
+
// - Use ECDSA keys
|
|
18
26
|
// - ALSO, get our nodeId set in our cookies, so HTTP requests can work as well
|
|
19
|
-
// - We will need
|
|
20
|
-
// - Then download the certs and try to get the user to install them, so chrome can use
|
|
21
|
-
// them? Otherwise there is no point of having certs clientside.
|
|
27
|
+
// - We will need callHTTPHandler to support this
|
|
22
28
|
|
|
23
29
|
// https://nodejs.org/en/knowledge/HTTP/servers/how-to-create-a-HTTPS-server/
|
|
24
30
|
|
|
@@ -38,6 +44,16 @@ export const getCertKeyPair = lazy((): { key: Buffer; cert: Buffer } => {
|
|
|
38
44
|
return { key, cert };
|
|
39
45
|
});
|
|
40
46
|
|
|
47
|
+
export function overrideCertKeyPair<T>(certKey: { key: Buffer; cert: Buffer; }, code: () => T): T {
|
|
48
|
+
let prevOverride = certKeyPairOverride;
|
|
49
|
+
certKeyPairOverride = certKey;
|
|
50
|
+
try {
|
|
51
|
+
return code();
|
|
52
|
+
} finally {
|
|
53
|
+
certKeyPairOverride = prevOverride;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
export function getTLSSocket(webSocket: ws.WebSocket) {
|
|
42
58
|
return (webSocket as any)._socket as tls.TLSSocket;
|
|
43
59
|
}
|
|
@@ -67,86 +83,59 @@ export const getNodeId = cacheWeak(function (webSocket: SenderInterface | ws.Web
|
|
|
67
83
|
if (webSocket.nodeId) {
|
|
68
84
|
return webSocket.nodeId;
|
|
69
85
|
}
|
|
70
|
-
throw new Error(`Missing nodeId. If it is from the browser, this likely means your websocket and HTTP request are using different domains (so the cookies are lost). If it is from NodeJs peer certificate must use an RSA key or EC key (which should have a .
|
|
86
|
+
throw new Error(`Missing nodeId. If it is from the browser, this likely means your websocket and HTTP request are using different domains (so the cookies are lost). If it is from NodeJs peer certificate must use an RSA key or EC key (which should have a .modulus property)`);
|
|
71
87
|
}
|
|
72
88
|
return nodeId;
|
|
73
89
|
});
|
|
74
90
|
|
|
91
|
+
export function getNodeIdFromCert(cert: { modulus: Buffer }) {
|
|
92
|
+
// Apparently some implementations strip preceding zeros, which makes sense, as it is a modulus so
|
|
93
|
+
// preceding zeros aren't needed.
|
|
94
|
+
let startIndex = 0;
|
|
95
|
+
while (startIndex < cert.modulus.length && cert.modulus[startIndex] === 0) {
|
|
96
|
+
startIndex++;
|
|
97
|
+
}
|
|
98
|
+
return sha256Hash(cert.modulus.slice(startIndex));
|
|
99
|
+
}
|
|
75
100
|
export function getNodeIdRaw(socket: tls.TLSSocket) {
|
|
76
101
|
let peerCert = socket.getPeerCertificate();
|
|
77
102
|
if (!peerCert) {
|
|
78
103
|
throw new Error("WebSocket connections must provided a peer certificate");
|
|
79
104
|
}
|
|
80
|
-
|
|
81
|
-
if (!
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
return sha256Hash(pubkey);
|
|
105
|
+
|
|
106
|
+
if (!peerCert.modulus) return undefined;
|
|
107
|
+
return getNodeIdFromCert({ modulus: Buffer.from(peerCert.modulus, "hex") });
|
|
85
108
|
}
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
110
|
+
/** NOTE: We create a factory, which embeds the key/cert information. Otherwise retries might use
|
|
111
|
+
* a different key/cert context.
|
|
112
|
+
*/
|
|
113
|
+
export function createWebsocketFactory(): (address: string, port: number) => SenderInterface {
|
|
114
|
+
|
|
89
115
|
if (!isNode()) {
|
|
90
116
|
// NOTE: We assume an HTTP request has already been made, which will setup a nodeId cookie
|
|
91
117
|
// (And as this point we can't even use peer certificates if we wanted to, as this must be done
|
|
92
118
|
// directly in the browser)
|
|
93
|
-
return
|
|
119
|
+
return (address: string, port: number) => {
|
|
120
|
+
console.log(`Connecting to ${address}:${port}`);
|
|
121
|
+
return new WebSocket(`wss://${address}:${port}`);
|
|
122
|
+
};
|
|
94
123
|
} else {
|
|
95
124
|
let { key, cert } = getCertKeyPair();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
125
|
+
let rejectUnauthorized = SocketFunction.rejectUnauthorized;
|
|
126
|
+
return (address: string, port: number) => {
|
|
127
|
+
console.log(`Connecting to ${address}:${port}`);
|
|
128
|
+
let webSocket = new ws.WebSocket(`wss://${address}:${port}`, {
|
|
129
|
+
cert,
|
|
130
|
+
key,
|
|
131
|
+
rejectUnauthorized,
|
|
132
|
+
ca: tls.rootCertificates.concat(SocketFunction.additionalTrustedRootCAs),
|
|
133
|
+
});
|
|
134
|
+
let result = Object.assign(webSocket, { socket: undefined as tls.TLSSocket | undefined });
|
|
135
|
+
webSocket.once("upgrade", e => {
|
|
136
|
+
result.socket = e.socket as tls.TLSSocket;
|
|
137
|
+
});
|
|
138
|
+
return result;
|
|
139
|
+
};
|
|
101
140
|
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
/*
|
|
107
|
-
const port = 2422;
|
|
108
|
-
let { key, cert } = getCertKeyPair();
|
|
109
|
-
console.log(process.argv);
|
|
110
|
-
if (process.argv.includes("--server")) {
|
|
111
|
-
|
|
112
|
-
let server = https.createServer({
|
|
113
|
-
key,
|
|
114
|
-
cert,
|
|
115
|
-
rejectUnauthorized: false,
|
|
116
|
-
requestCert: true
|
|
117
|
-
});
|
|
118
|
-
let listenPromise = new Promise<void>((resolve, error) => {
|
|
119
|
-
server.on("listening", () => {
|
|
120
|
-
resolve();
|
|
121
|
-
});
|
|
122
|
-
server.on("error", e => {
|
|
123
|
-
error(e);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
server.on("request", (request, response) => {
|
|
128
|
-
// TODO: Handle HTTP requests
|
|
129
|
-
// - HTTP CAN have a nodeId, simply through setting cookies
|
|
130
|
-
// - Cookies could always be set via a request before we open
|
|
131
|
-
// the websocket connection?
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const webSocketServer = new ws.Server({
|
|
135
|
-
noServer: true,
|
|
136
|
-
});
|
|
137
|
-
server.on("upgrade", (request, socket, upgradeHead) => {
|
|
138
|
-
webSocketServer.handleUpgrade(request, socket, upgradeHead, (ws) => {
|
|
139
|
-
console.log("peer", getTLSSocket(ws).getPeerCertificate()?.pubkey.toString("hex").slice(100));
|
|
140
|
-
console.log("cert", getTLSSocket(ws).getCertificate()?.pubkey.toString("hex").slice(100));
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
server.listen(2422, "127.0.0.1");
|
|
145
|
-
} else {
|
|
146
|
-
let socket = new ws.WebSocket(`wss://127.0.0.1:${port}`, { rejectUnauthorized: false, cert, key });
|
|
147
|
-
socket.on("open", () => {
|
|
148
|
-
console.log("peer", getTLSSocket(socket).getPeerCertificate()?.pubkey.toString("hex").slice(100));
|
|
149
|
-
console.log("cert", getTLSSocket(socket).getCertificate()?.pubkey.toString("hex").slice(100));
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
*/
|
|
141
|
+
}
|
package/src/webSocketServer.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { getCertKeyPair, getNodeId, getNodeIdRaw } from "./nodeAuthentication";
|
|
|
11
11
|
import debugbreak from "debugbreak";
|
|
12
12
|
import { cache } from "./caching";
|
|
13
13
|
import { getNodeIdFromRequest, getServerLocationFromRequest, httpCallHandler } from "./callHTTPHandler";
|
|
14
|
+
import { SocketFunction } from "../SocketFunction";
|
|
14
15
|
|
|
15
16
|
// TODO: Support conditional peer certificate requests, as it the certificate prompt
|
|
16
17
|
// seems suspicious in the browser (the user can just click cancel though).
|
|
@@ -41,8 +42,18 @@ export async function startSocketServer(
|
|
|
41
42
|
// so it is easy to read, and consistent.
|
|
42
43
|
let httpsServer = https.createServer({
|
|
43
44
|
...config,
|
|
44
|
-
rejectUnauthorized:
|
|
45
|
+
rejectUnauthorized: SocketFunction.rejectUnauthorized,
|
|
45
46
|
requestCert: true,
|
|
47
|
+
ca: tls.rootCertificates.concat(SocketFunction.additionalTrustedRootCAs),
|
|
48
|
+
});
|
|
49
|
+
httpsServer.on("connection", socket => {
|
|
50
|
+
console.log("Client connection established");
|
|
51
|
+
});
|
|
52
|
+
httpsServer.on("error", e => {
|
|
53
|
+
console.error(`Connection attempt error ${e.message}`);
|
|
54
|
+
});
|
|
55
|
+
httpsServer.on("tlsClientError", e => {
|
|
56
|
+
console.error(`TLS client error ${e.message}`);
|
|
46
57
|
});
|
|
47
58
|
|
|
48
59
|
|