socket-function 0.7.7 → 0.7.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SocketExposedInterface, CallContextType, SocketFunctionHook, SocketFunctionClientHook, SocketExposedShape, SocketRegistered, NetworkLocation, CallerContext, SocketExposedInterfaceClass, CallType } from "./SocketFunctionTypes";
2
2
  import { exposeClass, registerClass, registerGlobalClientHook, registerGlobalHook, runClientHooks } from "./src/callManager";
3
- import { SocketServerConfig, startSocketServer } from "./src/socketServer";
3
+ import { SocketServerConfig, startSocketServer } from "./src/webSocketServer";
4
4
  import { getCallFactoryNodeId, getCreateCallFactoryLocation, getNetworkLocationHash } from "./src/nodeCache";
5
5
  import { getCallProxy } from "./src/nodeProxy";
6
6
  import { Args } from "./src/types";
@@ -113,22 +113,20 @@ export class SocketFunction {
113
113
  }
114
114
 
115
115
  public static async connect(location: NetworkLocation | { address: string; port: number }): Promise<string> {
116
- if (!("localPort" in location)) {
116
+ if (!("listeningPorts" in location)) {
117
117
  location = {
118
118
  address: location.address,
119
- listeningPorts: [location.port],
120
- localPort: 0,
119
+ listeningPorts: [location.port]
121
120
  };
122
121
  }
123
122
  return await getCreateCallFactoryLocation(location);
124
123
  }
125
124
 
126
125
  public static connectSync(location: NetworkLocation | { address: string; port: number }): string {
127
- if (!("localPort" in location)) {
126
+ if (!("listeningPorts" in location)) {
128
127
  location = {
129
128
  address: location.address,
130
- listeningPorts: [location.port],
131
- localPort: 0,
129
+ listeningPorts: [location.port]
132
130
  };
133
131
  }
134
132
  let tempNodeId = "syncTempNodeId_" + getNetworkLocationHash(location);
@@ -65,17 +65,16 @@ export type CallerContext = {
65
65
  // them call functions directly using nodeId. Instead pass location, and have them use connect.
66
66
  // - nodeId SHOULD be used to identify users though, as it cannot be impersonated
67
67
  nodeId: string;
68
+ fromPort: number;
68
69
  location: NetworkLocation;
70
+ // The location of the server. It helps if it is told, due to the fact that one server
71
+ // can serve multiple domains.
72
+ serverLocation: NetworkLocation;
69
73
  };
70
74
 
71
75
  // IMPORTANT! Nodes at the same network location may vary, so you cannot store NetworkLocation
72
76
  // in a list of allowed users, otherwise they can be impersonated!
73
77
  export interface NetworkLocation {
74
78
  address: string;
75
- /** localPort is the port the connection was made from, which is often uninteresting.
76
- * It is useful internally, to help reduce collisions when a process restarts and
77
- * reconnects (as it may have the same source address, but the localPort will likely change).
78
- */
79
- localPort: number;
80
79
  listeningPorts: number[];
81
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "socket-function",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -13,7 +13,7 @@
13
13
  "ws": "^8.8.0"
14
14
  },
15
15
  "scripts": {
16
- "test": "yarn typenode ./nodeAuthentication.ts --server",
16
+ "test": "yarn typenode ./test/server.ts",
17
17
  "type": "yarn tsc --noEmit"
18
18
  }
19
19
  }
@@ -1,5 +1,5 @@
1
1
  import { CallerContext, CallType, NetworkLocation } from "../SocketFunctionTypes";
2
- import type * as ws from "ws";
2
+ import * as ws from "ws";
3
3
  import type * as net from "net";
4
4
  import { performLocalCall } from "./callManager";
5
5
  import { convertErrorStackToError, isNode } from "./misc";
@@ -34,20 +34,24 @@ export interface CallFactory {
34
34
  export async function callFactoryFromLocation(
35
35
  location: NetworkLocation
36
36
  ): Promise<CallFactory> {
37
- if (location.localPort !== 0) {
38
- throw new Error(`Expected localPort to be 0, but it was ${location.localPort}`);
39
- }
40
-
41
37
  let listeningPort = location.listeningPorts[0];
42
38
  if (typeof listeningPort !== "number") {
43
39
  throw new Error(`Expected listeningPorts to be provided, but it was empty`);
44
40
  }
45
41
 
46
- return await createCallFactory(undefined, location);
42
+ // Because we are the client, we don't get to know our NetworkLocation (but we shouldn't
43
+ // need to anyway).
44
+ let serverLocation: NetworkLocation = {
45
+ address: "localhost",
46
+ listeningPorts: [],
47
+ };
48
+
49
+ return await createCallFactory(undefined, location, serverLocation);
47
50
  }
48
51
 
49
52
  export async function callFactoryFromWS(
50
53
  webSocket: ws.WebSocket & { nodeId?: string },
54
+ serverLocation: NetworkLocation,
51
55
  ): Promise<CallFactory> {
52
56
  let socket = getTLSSocket(webSocket);
53
57
  let remoteAddress = socket.remoteAddress;
@@ -63,11 +67,10 @@ export async function callFactoryFromWS(
63
67
  // their process is dead, and is going to stay dead.
64
68
  let location: NetworkLocation = {
65
69
  address: remoteAddress,
66
- localPort: remotePort,
67
70
  listeningPorts: [],
68
71
  };
69
72
 
70
- return await createCallFactory(webSocket, location);
73
+ return await createCallFactory(webSocket, location, serverLocation);
71
74
  }
72
75
 
73
76
  export interface SenderInterface {
@@ -84,11 +87,20 @@ export interface SenderInterface {
84
87
  async function createCallFactory(
85
88
  webSocketBase: SenderInterface | undefined,
86
89
  location: NetworkLocation,
90
+ serverLocation: NetworkLocation,
87
91
  ): Promise<CallFactory> {
88
92
 
89
93
  let closedForever = false;
90
94
 
91
- let niceConnectionName = `${location.address}:${location.localPort}`;
95
+ let fromPort = 0;
96
+ if (webSocketBase && webSocketBase instanceof ws.WebSocket) {
97
+ let socket = getTLSSocket(webSocketBase);
98
+ fromPort = socket.remotePort ?? fromPort;
99
+ }
100
+ let niceConnectionName = `${location.address}:${location.listeningPorts.join("|")}`;
101
+ if (fromPort && location.listeningPorts.length === 0) {
102
+ niceConnectionName += `(${fromPort})`;
103
+ }
92
104
 
93
105
  let retriesEnabled = location.listeningPorts.length === 0;
94
106
 
@@ -110,7 +122,7 @@ async function createCallFactory(
110
122
  let nextSeqNum = Math.random();
111
123
 
112
124
  const pendingNodeId = "PENDING";
113
- let callerContext: CallerContext = { location, nodeId: pendingNodeId };
125
+ let callerContext: CallerContext = { location, nodeId: pendingNodeId, serverLocation, fromPort };
114
126
  let webSocket!: SenderInterface;
115
127
  if (!webSocketBase) {
116
128
  await tryToReconnect();
@@ -176,7 +188,7 @@ async function createCallFactory(
176
188
  call.callback({
177
189
  isReturn: true,
178
190
  result: undefined,
179
- error: `Connection lost to ${location.address}:${location.localPort}`,
191
+ error: `Connection lost to ${niceConnectionName}`,
180
192
  seqNum: call.call.seqNum,
181
193
  });
182
194
  }
@@ -317,7 +329,7 @@ async function createCallFactory(
317
329
  location,
318
330
  async performCall(call: CallType) {
319
331
  if (closedForever) {
320
- throw new Error(`Connection lost to ${location.address}:${location.localPort}`);
332
+ throw new Error(`Connection lost to ${niceConnectionName}`);
321
333
  }
322
334
 
323
335
  let seqNum = nextSeqNum++;
@@ -2,13 +2,13 @@ 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 } from "../SocketFunctionTypes";
5
+ import { CallerContext, CallType, NetworkLocation } from "../SocketFunctionTypes";
6
6
  import { performLocalCall } from "./callManager";
7
7
  import { getNodeIdRaw } from "./nodeAuthentication";
8
8
  import debugbreak from "debugbreak";
9
9
  import * as cookie from "cookie";
10
10
 
11
- const nodeIdCookie = "node-id3";
11
+ const nodeIdCookie = "node-id4";
12
12
 
13
13
  let defaultHTTPCall: CallType | undefined;
14
14
 
@@ -24,6 +24,23 @@ export function getNodeIdFromRequest(request: http.IncomingMessage): string | un
24
24
  if (!value.startsWith(cookieNodeIdPrefix)) return undefined;
25
25
  return value;
26
26
  }
27
+ export function getServerLocationFromRequest(request: http.IncomingMessage): NetworkLocation {
28
+ let host = request.headers.host;
29
+ if (!host) {
30
+ throw new Error(`Missing host in request headers`);
31
+ }
32
+ let port = 443;
33
+ if (host.includes(":")) {
34
+ port = +host.split(":")[1];
35
+ host = host.split(":")[0];
36
+ }
37
+ return {
38
+ address: host,
39
+ // This is OUR location, so whatever they connected to us... we must be listening on!
40
+ // (and the localPort doesn't matter in this case)
41
+ listeningPorts: [port],
42
+ };
43
+ }
27
44
 
28
45
  export async function httpCallHandler(request: http.IncomingMessage, response: http.ServerResponse) {
29
46
  try {
@@ -85,11 +102,12 @@ export async function httpCallHandler(request: http.IncomingMessage, response: h
85
102
 
86
103
  let caller: CallerContext = {
87
104
  nodeId,
105
+ fromPort: port,
88
106
  location: {
89
107
  address,
90
- localPort: port,
91
108
  listeningPorts: [],
92
- }
109
+ },
110
+ serverLocation: getServerLocationFromRequest(request),
93
111
  };
94
112
 
95
113
  let classGuid = urlObj.searchParams.get("classGuid");
@@ -67,7 +67,7 @@ export const getNodeId = cacheWeak(function (webSocket: SenderInterface | ws.Web
67
67
  if (webSocket.nodeId) {
68
68
  return webSocket.nodeId;
69
69
  }
70
- throw new Error(`Peer certificate must use an RSA key or EC key (which should have a .pubkey property)`);
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 .pubkey property)`);
71
71
  }
72
72
  return nodeId;
73
73
  });
package/src/nodeCache.ts CHANGED
@@ -19,7 +19,7 @@ const nodeCache = new Map<string, {
19
19
  const locationLookup = new Map<string, MaybePromise<string>>();
20
20
 
21
21
  export function getNetworkLocationHash(location: NetworkLocation): string {
22
- return location.address + ":" + location.localPort + "=" + location.listeningPorts.join("|");
22
+ return location.address + ":" + location.listeningPorts.join("|");
23
23
  }
24
24
 
25
25
  // NOTE: For client connections, at which point we have the nodeId, location and callFactory.
@@ -10,7 +10,7 @@ import { registerNodeClient } from "./nodeCache";
10
10
  import { getCertKeyPair, getNodeId, getNodeIdRaw } from "./nodeAuthentication";
11
11
  import debugbreak from "debugbreak";
12
12
  import { cache } from "./caching";
13
- import { getNodeIdFromRequest, httpCallHandler } from "./callHTTPHandler";
13
+ import { getNodeIdFromRequest, getServerLocationFromRequest, httpCallHandler } from "./callHTTPHandler";
14
14
 
15
15
  // TODO: Support conditional peer certificate requests, as it the certificate prompt
16
16
  // seems suspicious in the browser (the user can just click cancel though).
@@ -59,7 +59,7 @@ export async function startSocketServer(
59
59
  let requestNodeId = getNodeIdFromRequest(request);
60
60
  Object.assign(ws, { nodeId: requestNodeId });
61
61
 
62
- let clientCallFactory = await callFactoryFromWS(ws);
62
+ let clientCallFactory = await callFactoryFromWS(ws, getServerLocationFromRequest(request));
63
63
  registerNodeClient(clientCallFactory);
64
64
  });
65
65
  });
package/test/client.ts CHANGED
@@ -7,6 +7,7 @@ import { setFlag } from "../require/compileFlags";
7
7
  import { SocketFunction } from "../SocketFunction";
8
8
  import { Test } from "./shared";
9
9
 
10
+ import "../require/CSSShim";
10
11
  import "./client.css";
11
12
  import { isNode } from "../src/misc";
12
13
 
@@ -28,7 +29,7 @@ async function main() {
28
29
 
29
30
  const port = 2542;
30
31
 
31
- let serverId = await SocketFunction.connect({ port, address: "letx.ca" });
32
+ let serverId = await SocketFunction.connect({ port, address: "localhost" });
32
33
  let test = await Test.nodes[serverId].add(1, 2);
33
34
  console.log(`${test}=${1 + 2}`);
34
35