querysub 0.647.0 → 0.648.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.647.0",
3
+ "version": "0.648.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -29,15 +29,22 @@ const MAX_CHANGE_IDENTITY_TIMEOUT = timeInMinute * 5;
29
29
  const MOUNT_WAIT_TIMEOUT = timeInMinute * 3;
30
30
 
31
31
  let callerInfo = new Map<CallerContext, {
32
- reconnectNodeId: string | Promise<string | Error> | undefined;
33
- resolveReconnectNodeId?: (value: string | Error) => void;
32
+ reconnectNodeId: string | Promise<string>;
33
+ reconnectNodeIdPromiseObj: PromiseObj<string> | undefined;
34
34
  certCommonName: string;
35
35
  machineId: string;
36
36
  cert: CertInfo;
37
37
  pubKey: Buffer;
38
38
  pubKeyShort: number;
39
39
  }>();
40
- const callerInfoErrorString = `Internal error, caller did not updated their identity. Is this an HTTPS call (instead of a websocket call)? The caller should import the server controller, which imports this function, which will add a client hook to always update the identity`;
40
+
41
+ function getCallerInfoAssert(callerContext: CallerContext) {
42
+ let info = callerInfo.get(callerContext);
43
+ if (!info) {
44
+ throw new Error(`Internal error, caller did not updated their identity. Is this an HTTPS call (instead of a websocket call)? The caller should import the server controller, which imports this function, which will add a client hook to always update the identity`);
45
+ }
46
+ return info;
47
+ }
41
48
 
42
49
  /** Gets the nodeId of the caller suitable for reconnecting (to the same process).
43
50
  * - Also useful for logs, to identify a node on the network.
@@ -51,37 +58,19 @@ export function IdentityController_getReconnectNodeId(callerContext: CallerConte
51
58
  let info = callerInfo.get(callerContext);
52
59
  if (!info) {
53
60
  if (allowUndefined) return undefined;
54
- throw new Error(callerInfoErrorString);
61
+ info = getCallerInfoAssert(callerContext);
55
62
  }
56
- let value = info.reconnectNodeId;
57
- if (typeof value !== "string") return undefined;
58
- return value;
63
+ if (typeof info.reconnectNodeId === "string") {
64
+ return info.reconnectNodeId;
65
+ }
66
+ return undefined;
59
67
  }
60
68
  export async function IdentityController_getReconnectNodeIdAssert(callerContext: CallerContext): Promise<string> {
61
69
  if (!isClientNodeId(callerContext.nodeId)) {
62
70
  return callerContext.nodeId;
63
71
  }
64
- let info = callerInfo.get(callerContext);
65
- if (!info) {
66
- throw new Error(callerInfoErrorString);
67
- }
68
- let valueBase = info.reconnectNodeId;
69
- let value: string | Error | undefined;
70
- if (valueBase instanceof Promise) {
71
- value = await valueBase;
72
- } else {
73
- value = valueBase;
74
- }
75
- if (value instanceof Error) {
76
- throw value;
77
- }
78
- if (!value) {
79
- console.error(`Caller did not mount before connecting. This call requires the caller to be listening.`, {
80
- callerNodeId: callerContext.nodeId,
81
- });
82
- throw new Error(`Caller did not mount before connecting. This call requires the caller to be listening.`);
83
- }
84
- return value;
72
+ let info = getCallerInfoAssert(callerContext);
73
+ return await info.reconnectNodeId;
85
74
  }
86
75
  export function IdentityController_getSecureIP(callerContext: CallerContext): string {
87
76
  return getNodeIdIP(callerContext.nodeId);
@@ -95,9 +84,11 @@ export function IdentityController_getCurrentReconnectNodeId(): string | undefin
95
84
 
96
85
  export function debugNodeId(nodeId: string) {
97
86
  let info = Array.from(callerInfo.entries()).find(x => x[0].nodeId === nodeId);
98
- let value = info?.[1].reconnectNodeId;
99
- if (typeof value !== "string") return nodeId;
100
- return value;
87
+ let reconnectNodeId = info?.[1].reconnectNodeId;
88
+ if (typeof reconnectNodeId !== "string") {
89
+ return nodeId;
90
+ }
91
+ return reconnectNodeId;
101
92
  };
102
93
  (globalThis as any).debugNodeId = debugNodeId;
103
94
 
@@ -118,21 +109,19 @@ export function IdentityController_getMachineId(callerContext: CallerContext, al
118
109
  let info = callerInfo.get(callerContext);
119
110
  if (!info) {
120
111
  if (allowEmpty) return "";
121
- throw new Error(callerInfoErrorString);
112
+ info = getCallerInfoAssert(callerContext);
122
113
  }
123
114
  return info.machineId;
124
115
  }
125
116
 
126
117
  export type CertInfo = { certPEM: Buffer | string; issuerPEM: Buffer | string; };
127
118
  export function IdentityController_getCertInfo(callerContext: CallerContext): CertInfo {
128
- let info = callerInfo.get(callerContext);
129
- if (!info) throw new Error(callerInfoErrorString);
119
+ let info = getCallerInfoAssert(callerContext);
130
120
  return info.cert;
131
121
  }
132
122
 
133
123
  export function IdentityController_getPubKeyShort(callerContext: CallerContext): number {
134
- let info = callerInfo.get(callerContext);
135
- if (!info) throw new Error(callerInfoErrorString);
124
+ let info = getCallerInfoAssert(callerContext);
136
125
  return info.pubKeyShort;
137
126
  }
138
127
  export const IdentityController_getOwnPubKeyShort = lazy((): number => {
@@ -149,7 +138,7 @@ export interface ChangeIdentityPayload {
149
138
  serverId: string;
150
139
  mountedPort: number | undefined;
151
140
  debugEntryPoint: string | undefined;
152
- clientIsNode: boolean;
141
+ callerIsNode: boolean;
153
142
  }
154
143
  class IdentityControllerBase {
155
144
  // IMPORTANT! We HAVE to call changeIdentity NOT JUST because we can't use peer certificates in the browser, BUT, also
@@ -167,7 +156,7 @@ class IdentityControllerBase {
167
156
  throw new Error(`Signed payload too old, ${payload.time} < ${signedThreshold} from ${caller.localNodeId} (${caller.nodeId})`);
168
157
  }
169
158
 
170
- if (payload.clientIsNode && payload.serverId !== getOwnNodeId()) {
159
+ if (payload.callerIsNode && payload.serverId !== getOwnNodeId()) {
171
160
  // This is extremely common when we reuse ports, which we do frequently for the edge nodes.
172
161
  throw new Error(`You tried to contact another server. We are ${getOwnNodeId()}, you tried to contact ${payload.serverId}.`);
173
162
  }
@@ -180,7 +169,7 @@ class IdentityControllerBase {
180
169
  throw new Error(`Identity is for another server! The connection is calling us ${localNodeId}, but signature is for ${payload.serverId}`);
181
170
  }
182
171
  // If they're calling from the browser, then they're not going to be able to use our machine ID, etc. However, they should be calling an actual https node, so it should still be secure for them.
183
- if (payload.clientIsNode) {
172
+ if (payload.callerIsNode) {
184
173
  let calledMachineId = getMachineId(payload.serverId, getDomain());
185
174
  if (calledMachineId !== "127-0-0-1" && calledMachineId !== getOwnMachineId(getDomain())) {
186
175
  throw new Error(`Tried to call a different machine. We are ${getOwnMachineId(getDomain())}, they called ${calledMachineId}`);
@@ -202,19 +191,22 @@ class IdentityControllerBase {
202
191
  // to use HTTPS, so connecting over the IP won't work! (unless they turn off certificate validation,
203
192
  // which we shouldn't do...)
204
193
  let certCommonName = getCommonName(payload.cert);
205
- let reconnectNodeId: string | Promise<string | Error> | undefined;
206
- let resolveReconnectNodeId: ((value: string | Error) => void) | undefined;
194
+ let reconnectNodeId: string | Promise<string>;
195
+ let reconnectNodeIdPromiseObj: PromiseObj<string> | undefined;
207
196
  if (payload.mountedPort) {
208
197
  reconnectNodeId = getNodeId(certCommonName, payload.mountedPort);
209
198
  } else {
210
- let pending = new PromiseObj<string | Error>();
211
- reconnectNodeId = pending.promise;
212
- resolveReconnectNodeId = pending.resolve;
199
+ reconnectNodeIdPromiseObj = new PromiseObj<string>();
200
+ reconnectNodeId = reconnectNodeIdPromiseObj.promise;
213
201
  setTimeout(() => {
214
- pending.resolve(new Error(`Caller did not mount within ${formatTime(MOUNT_WAIT_TIMEOUT)} of connecting. This call requires the caller to be listening.`));
202
+ reconnectNodeIdPromiseObj?.reject(new Error(`Caller did not call setMountedPort within ${formatTime(MOUNT_WAIT_TIMEOUT)} of connecting. This call requires the caller to be listening.`));
215
203
  }, MOUNT_WAIT_TIMEOUT);
216
204
  }
217
205
 
206
+ if (!payload.callerIsNode) {
207
+ reconnectNodeIdPromiseObj?.reject(new Error(`The caller says they are a client, so they are never going to have a reconnect node id`));
208
+ }
209
+
218
210
  let pubKey = getPublicIdentifier(payload.cert);
219
211
  let machineId = getMachineId(getCommonName(payload.certIssuer), getDomain());
220
212
 
@@ -223,7 +215,7 @@ class IdentityControllerBase {
223
215
  machineId,
224
216
  certCommonName,
225
217
  reconnectNodeId,
226
- resolveReconnectNodeId,
218
+ reconnectNodeIdPromiseObj,
227
219
  pubKey,
228
220
  pubKeyShort: getShortNumber(pubKey),
229
221
  });
@@ -249,11 +241,11 @@ class IdentityControllerBase {
249
241
  @measureFnc
250
242
  public async setMountedPort(mountedPort: number) {
251
243
  const caller = SocketFunction.getCaller();
252
- let info = callerInfo.get(caller);
253
- if (!info) throw new Error(callerInfoErrorString);
244
+ let info = getCallerInfoAssert(caller);
245
+ if (typeof info.reconnectNodeId === "string") throw new Error(`Already have reconnectNodeId, not sure why we are being given another, Have ${info.reconnectNodeId}, given port: ${mountedPort}`);
254
246
  let reconnectNodeId = getNodeId(info.certCommonName, mountedPort);
255
247
  info.reconnectNodeId = reconnectNodeId;
256
- info.resolveReconnectNodeId?.(reconnectNodeId);
248
+ info.reconnectNodeIdPromiseObj?.resolve(reconnectNodeId);
257
249
  console.info(`Caller mounted after connecting, set reconnect node id`, {
258
250
  clientId: caller.nodeId,
259
251
  reconnectNodeId,
@@ -290,7 +282,7 @@ const changeIdentityOnce = cacheWeak(async function changeIdentityOnce(connectio
290
282
  certIssuer: issuer.cert.toString(),
291
283
  mountedPort: getNodeIdLocation(SocketFunction.mountedNodeId)?.port,
292
284
  debugEntryPoint: isServer() ? process.argv[1] : "browser",
293
- clientIsNode: isServer() && !isIpDomain(nodeId),
285
+ callerIsNode: isServer() && !isIpDomain(nodeId),
294
286
  };
295
287
  let signature = sign(threadKeyCert, payload);
296
288
  await timeoutToError(
@@ -302,13 +294,9 @@ const changeIdentityOnce = cacheWeak(async function changeIdentityOnce(connectio
302
294
  logErrors((async () => {
303
295
  await SocketFunction.mountPromise;
304
296
  let mountedPort = getNodeIdLocation(SocketFunction.mountedNodeId)?.port;
305
- if (!mountedPort) return;
297
+ if (!mountedPort) throw new Error(`Mounted after connecting to ${nodeId}, but no mounted port found? mounted node id: ${SocketFunction.mountedNodeId}`);
306
298
  console.info(`Mounted after connecting to ${nodeId}, sending mounted port ${mountedPort}`);
307
- await timeoutToError(
308
- MAX_CHANGE_IDENTITY_TIMEOUT,
309
- IdentityController.nodes[nodeId].setMountedPort(mountedPort),
310
- () => new Error(`Timeout calling setMountedPort for ${nodeId}`)
311
- );
299
+ await IdentityController.nodes[nodeId].setMountedPort(mountedPort);
312
300
  })());
313
301
  }
314
302
  });