@swf2es/desktop 0.1.16 → 0.1.17

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.
Files changed (54) hide show
  1. package/README.md +41 -1
  2. package/dist/main/air.d.ts +3 -3
  3. package/dist/main/air.d.ts.map +1 -1
  4. package/dist/main/air.js +17 -8
  5. package/dist/main/air.js.map +1 -1
  6. package/dist/main/case-paths.d.ts +12 -0
  7. package/dist/main/case-paths.d.ts.map +1 -0
  8. package/dist/main/case-paths.js +84 -0
  9. package/dist/main/case-paths.js.map +1 -0
  10. package/dist/main/connections.d.ts +20 -1
  11. package/dist/main/connections.d.ts.map +1 -1
  12. package/dist/main/connections.js +71 -8
  13. package/dist/main/connections.js.map +1 -1
  14. package/dist/main/main.js +80 -14
  15. package/dist/main/main.js.map +1 -1
  16. package/dist/main/network.d.ts +10 -0
  17. package/dist/main/network.d.ts.map +1 -1
  18. package/dist/main/network.js +111 -35
  19. package/dist/main/network.js.map +1 -1
  20. package/dist/main/proxy.d.ts +48 -0
  21. package/dist/main/proxy.d.ts.map +1 -0
  22. package/dist/main/proxy.js +402 -0
  23. package/dist/main/proxy.js.map +1 -0
  24. package/dist/main/sandbox.d.ts.map +1 -1
  25. package/dist/main/sandbox.js +2 -1
  26. package/dist/main/sandbox.js.map +1 -1
  27. package/dist/main/settings.d.ts +2 -0
  28. package/dist/main/settings.d.ts.map +1 -1
  29. package/dist/main/settings.js +4 -0
  30. package/dist/main/settings.js.map +1 -1
  31. package/dist/main/sockets.d.ts +4 -2
  32. package/dist/main/sockets.d.ts.map +1 -1
  33. package/dist/main/sockets.js +6 -4
  34. package/dist/main/sockets.js.map +1 -1
  35. package/dist/main/websocket-connections.d.ts +11 -0
  36. package/dist/main/websocket-connections.d.ts.map +1 -1
  37. package/dist/main/websocket-connections.js +72 -4
  38. package/dist/main/websocket-connections.js.map +1 -1
  39. package/dist/main/websockets.d.ts +3 -2
  40. package/dist/main/websockets.d.ts.map +1 -1
  41. package/dist/main/websockets.js +4 -3
  42. package/dist/main/websockets.js.map +1 -1
  43. package/package.json +7 -7
  44. package/src/main/air.ts +18 -8
  45. package/src/main/case-paths.ts +97 -0
  46. package/src/main/connections.ts +90 -8
  47. package/src/main/main.ts +105 -20
  48. package/src/main/network.ts +140 -37
  49. package/src/main/proxy.ts +497 -0
  50. package/src/main/sandbox.ts +2 -1
  51. package/src/main/settings.ts +5 -0
  52. package/src/main/sockets.ts +7 -4
  53. package/src/main/websocket-connections.ts +84 -4
  54. package/src/main/websockets.ts +4 -2
@@ -1,3 +1,10 @@
1
+ // One page's air.net.WebSocket connections, made with the WHATWG WebSocket
2
+ // of Electron's Node: what the WebSocket bridge (websockets.ts) holds for
3
+ // each page, apart from Electron so that node runs it in the tests
4
+ // (tests/desktop/websocket-connections.test.ts).
5
+ import { isIP } from "node:net";
6
+ import * as tls from "node:tls";
7
+ import { connectThrough } from "./proxy.js";
1
8
  /** As many as a page may hold open at once; past it a connection is refused. */
2
9
  const MAX_OPEN = 64;
3
10
  /** The longest URL, and the most and longest subprotocols, a page may ask for. */
@@ -25,25 +32,86 @@ export function hasWebSocket() {
25
32
  * made from the class of the dispatcher undici keeps for everything else.
26
33
  */
27
34
  export function unverifiedDispatcher() {
35
+ const Agent = agentClass();
36
+ if (!Agent) {
37
+ return null;
38
+ }
39
+ try {
40
+ const agent = new Agent({
41
+ connect: { rejectUnauthorized: false },
42
+ });
43
+ return typeof agent.dispatch === "function" ? agent : null;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ /** undici's Agent, the class of the dispatcher it keeps for everything else; null where none. */
50
+ function agentClass() {
28
51
  // Naming the global loads undici, which then sets its dispatcher.
29
52
  if (!hasWebSocket()) {
30
53
  return null;
31
54
  }
32
55
  const shared = globalThis[Symbol.for("undici.globalDispatcher.1")];
33
56
  const Agent = shared?.constructor;
34
- if (typeof Agent !== "function" || Agent.name !== "Agent") {
57
+ return typeof Agent === "function" && Agent.name === "Agent"
58
+ ? Agent
59
+ : null;
60
+ }
61
+ /**
62
+ * What sends every client's requests through `proxy` (--proxy): a tunnel to
63
+ * the URL's host, by name for the proxy to resolve, and TLS over it for
64
+ * wss:, its certificate unverified where `unverified` says so of its host.
65
+ * `warn` is told why a proxy did not make one. Null where this Node gives
66
+ * no way to make one, as unverifiedDispatcher.
67
+ */
68
+ export function proxiedDispatcher(proxy, unverified, warn = () => { }) {
69
+ const Agent = agentClass();
70
+ if (!Agent) {
35
71
  return null;
36
72
  }
37
- try {
38
- const agent = new Agent({
39
- connect: { rejectUnauthorized: false },
73
+ // undici's connector: its options name the target, and its callback takes the socket made.
74
+ const connect = (options, done) => {
75
+ const host = options.hostname.replace(/^\[(.*)\]$/, "$1").toLowerCase();
76
+ const https = options.protocol === "https:";
77
+ const port = Number(options.port) || (https ? 443 : 80);
78
+ connectThrough(proxy, host, port).then((tunnel) => {
79
+ if (!https) {
80
+ done(null, tunnel);
81
+ return;
82
+ }
83
+ const secure = tls.connect({
84
+ socket: tunnel,
85
+ servername: isIP(host) ? undefined : (options.servername ?? host),
86
+ ALPNProtocols: ["http/1.1"],
87
+ ...(unverified(host) ? { rejectUnauthorized: false } : {}),
88
+ });
89
+ const failed = (error) => done(error, null);
90
+ secure.once("error", failed);
91
+ secure.once("secureConnect", () => {
92
+ secure.removeListener("error", failed);
93
+ done(null, secure);
94
+ });
95
+ }, (error) => {
96
+ warn(`no WebSocket to ${host}:${port}: ${error.message}`);
97
+ done(error, null);
40
98
  });
99
+ };
100
+ try {
101
+ const agent = new Agent({ connect });
41
102
  return typeof agent.dispatch === "function" ? agent : null;
42
103
  }
43
104
  catch {
44
105
  return null;
45
106
  }
46
107
  }
108
+ /** An opener whose every connection is `dispatcher`'s: proxiedDispatcher's. */
109
+ export function dispatchedOpener(dispatcher) {
110
+ return (url, protocols) => {
111
+ const Client = globalClient();
112
+ return new Client(url, { protocols, dispatcher });
113
+ };
114
+ }
47
115
  /**
48
116
  * An opener that leaves a wss: server's certificate unverified where
49
117
  * `unverified` says so of its host, through `dispatcher`
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-connections.js","sourceRoot":"","sources":["../../src/main/websocket-connections.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-connections.js","sourceRoot":"","sources":["../../src/main/websocket-connections.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ import { type Opener } from "./websocket-connections.ts";
5
5
  * connection made only where `permit` allows its URL, with `open` if
6
6
  * given. `log`, where given, is told each connection asked for, opened,
7
7
  * refused, failed and closed (--log-network), and with `data` what each
8
- * sends and receives too (--log-sockets).
8
+ * sends and receives too (--log-sockets), the connections' lines ending
9
+ * in `via`.
9
10
  */
10
- export declare function bridgeWebSockets(trusted: (event: IpcMainEvent) => boolean, permit: (url: string) => boolean, open: Opener | undefined, log?: ((line: string) => void) | null, data?: boolean): void;
11
+ export declare function bridgeWebSockets(trusted: (event: IpcMainEvent) => boolean, permit: (url: string) => boolean, open: Opener | undefined, log?: ((line: string) => void) | null, data?: boolean, via?: string): void;
11
12
  //# sourceMappingURL=websockets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websockets.d.ts","sourceRoot":"","sources":["../../src/main/websockets.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAA6B,MAAM,UAAU,CAAC;AAExE,OAAO,EACL,KAAK,MAAM,EAIZ,MAAM,4BAA4B,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,EACzC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,GAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAW,EAC3C,IAAI,UAAQ,GACX,IAAI,CAwFN"}
1
+ {"version":3,"file":"websockets.d.ts","sourceRoot":"","sources":["../../src/main/websockets.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAA6B,MAAM,UAAU,CAAC;AAExE,OAAO,EACL,KAAK,MAAM,EAIZ,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,EACzC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,GAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAW,EAC3C,IAAI,UAAQ,EACZ,GAAG,SAAK,GACP,IAAI,CAwFN"}
@@ -10,9 +10,10 @@ import { validProtocols, validWebSocketUrl, WebSocketConnections, } from "./webs
10
10
  * connection made only where `permit` allows its URL, with `open` if
11
11
  * given. `log`, where given, is told each connection asked for, opened,
12
12
  * refused, failed and closed (--log-network), and with `data` what each
13
- * sends and receives too (--log-sockets).
13
+ * sends and receives too (--log-sockets), the connections' lines ending
14
+ * in `via`.
14
15
  */
15
- export function bridgeWebSockets(trusted, permit, open, log = null, data = false) {
16
+ export function bridgeWebSockets(trusted, permit, open, log = null, data = false, via = "") {
16
17
  const pages = new Map();
17
18
  const connectionsOf = (contents) => {
18
19
  const known = pages.get(contents);
@@ -66,7 +67,7 @@ export function bridgeWebSockets(trusted, permit, open, log = null, data = false
66
67
  // As the client will read it: what is said of it has nothing a terminal would act on.
67
68
  const href = new URL(url).href;
68
69
  const allowed = permit(href);
69
- log?.(webSocketLine(id, `${allowed ? "connecting to" : "refused"} ${href}`));
70
+ log?.(webSocketLine(id, `${allowed ? `connecting to ${href}${via}` : `refused ${href}`}`));
70
71
  if (allowed) {
71
72
  connections.connect(id, href, protocols);
72
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"websockets.js","sourceRoot":"","sources":["../../src/main/websockets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websockets.js","sourceRoot":"","sources":["../../src/main/websockets.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swf2es/desktop",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "swf2es's desktop app: local and remote SWFs, and AIR applications, in an Electron window",
5
5
  "keywords": [
6
6
  "swf",
@@ -35,12 +35,12 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "electron": "44.10.2",
38
- "@swf2es/context3d": "0.1.16",
39
- "@swf2es/format": "0.1.16",
40
- "@swf2es/codegen": "0.1.16",
41
- "@swf2es/player": "0.1.16",
42
- "@swf2es/web": "0.1.16",
43
- "@swf2es/player-hosts": "0.1.16"
38
+ "@swf2es/codegen": "0.1.17",
39
+ "@swf2es/format": "0.1.17",
40
+ "@swf2es/player": "0.1.17",
41
+ "@swf2es/web": "0.1.17",
42
+ "@swf2es/player-hosts": "0.1.17",
43
+ "@swf2es/context3d": "0.1.17"
44
44
  },
45
45
  "scripts": {
46
46
  "fetch-electron": "node node_modules/electron/install.js",
package/src/main/air.ts CHANGED
@@ -22,6 +22,7 @@ import { homedir } from "node:os";
22
22
  import { basename, dirname, join, resolve, sep } from "node:path";
23
23
  import { readAirDescriptor } from "@swf2es/format";
24
24
  import type { AirFileStat, AirLaunch } from "../shared/api.js";
25
+ import { resolveCase } from "./case-paths.ts";
25
26
 
26
27
  /** What the command line asks adl's way: the descriptor, the application's directory, the arguments. */
27
28
  export interface AirCommand {
@@ -78,7 +79,7 @@ export function airLaunch(
78
79
  );
79
80
  mkdirSync(applicationStorage, { recursive: true });
80
81
  return {
81
- content: resolve(application, ...descriptor.content.split("/")),
82
+ content: resolveCase(resolve(application, ...descriptor.content.split("/"))),
82
83
  relative: descriptor.content,
83
84
  launch: {
84
85
  descriptor: xml,
@@ -95,7 +96,8 @@ export function airLaunch(
95
96
  }
96
97
 
97
98
  /** What is at `path`, as File reads it; null where nothing is. */
98
- export function statOf(path: string): AirFileStat | null {
99
+ export function statOf(asked: string): AirFileStat | null {
100
+ const path = resolveCase(asked);
99
101
  try {
100
102
  const s = statSync(path);
101
103
  const link = lstatSync(path).isSymbolicLink();
@@ -116,7 +118,7 @@ export function statOf(path: string): AirFileStat | null {
116
118
  /** The names in the directory at `path`; null where it is none. */
117
119
  export function listOf(path: string): string[] | null {
118
120
  try {
119
- return readdirSync(path);
121
+ return readdirSync(resolveCase(path));
120
122
  } catch {
121
123
  return null;
122
124
  }
@@ -125,7 +127,7 @@ export function listOf(path: string): string[] | null {
125
127
  /** The bytes of the file at `path`, as FileStream's open reads them at once; null where none can be read. */
126
128
  export function readOf(path: string): Uint8Array | null {
127
129
  try {
128
- return new Uint8Array(readFileSync(path));
130
+ return new Uint8Array(readFileSync(resolveCase(path)));
129
131
  } catch {
130
132
  return null;
131
133
  }
@@ -222,7 +224,8 @@ export class EncryptedItems {
222
224
  * `length` long, made with its directories where it is not: FileStream's
223
225
  * writes. False where it cannot be written.
224
226
  */
225
- export function writeOf(path: string, bytes: Uint8Array, offset: number, length: number): boolean {
227
+ export function writeOf(asked: string, bytes: Uint8Array, offset: number, length: number): boolean {
228
+ const path = resolveCase(asked);
226
229
  return attempt(() => {
227
230
  mkdirSync(dirname(path), { recursive: true });
228
231
  // "a+" would only append; "r+" needs the file there, which "a" makes without emptying it.
@@ -239,16 +242,23 @@ export function writeOf(path: string, bytes: Uint8Array, offset: number, length:
239
242
 
240
243
  /** Makes the directory at `path` and those it is in; false where it cannot. */
241
244
  export function createDirectoryOf(path: string): boolean {
242
- return attempt(() => mkdirSync(path, { recursive: true }));
245
+ return attempt(() => mkdirSync(resolveCase(path), { recursive: true }));
243
246
  }
244
247
 
245
248
  /** Removes the file or directory at `path`, with all in it; false where it cannot. */
246
249
  export function removeOf(path: string): boolean {
247
- return attempt(() => rmSync(path, { recursive: true }));
250
+ return attempt(() => rmSync(resolveCase(path), { recursive: true }));
248
251
  }
249
252
 
250
253
  /** Moves what is at `from` to `to`, its directories made; false where it cannot. */
251
- export function moveOf(from: string, to: string): boolean {
254
+ export function moveOf(askedFrom: string, askedTo: string): boolean {
255
+ const from = resolveCase(askedFrom);
256
+ let to = resolveCase(askedTo);
257
+ // A rename of its case alone, which Windows makes: the name as given, in its directory as found.
258
+ if (to === from) {
259
+ to = join(resolveCase(dirname(askedTo)), basename(askedTo));
260
+ }
261
+
252
262
  return attempt(() => {
253
263
  mkdirSync(dirname(to), { recursive: true });
254
264
  try {
@@ -0,0 +1,97 @@
1
+ // Local paths as a case-insensitive file system finds them. AIR runs on
2
+ // Windows and macOS, whose file systems ignore case, so an AIR application
3
+ // or a SWF made there may name a file in any case: maps/Town.swf for
4
+ // maps/town.swf. On Linux such a path finds nothing, so where the exact
5
+ // path is missing each missing segment is taken as the one entry of its
6
+ // directory equal to it ignoring case. Names are compared as NFC,
7
+ // lowercased by toLowerCase(): close enough to how NTFS and APFS fold
8
+ // case, and APFS keeps a name's normalization, as NFC compares it.
9
+ // Apart from Electron, so that node tests it (tests/desktop/case-paths.test.ts).
10
+ import { lstatSync, readdirSync } from "node:fs";
11
+ import { isAbsolute, parse, sep } from "node:path";
12
+
13
+ /** Whether this system's file system tells names apart by case: Linux's do; Windows' and macOS's do not. */
14
+ const CASE_SENSITIVE = process.platform === "linux";
15
+
16
+ /** The directories already said, on stderr, to hold names that differ only in case. */
17
+ const told = new Set<string>();
18
+
19
+ const fold = (name: string) => name.normalize("NFC").toLowerCase();
20
+
21
+ function exists(path: string): boolean {
22
+ try {
23
+ lstatSync(path);
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ /**
31
+ * `path`, absolute, as Windows would find it: unchanged where it is there
32
+ * exactly; otherwise from the deepest ancestor that is there, each missing
33
+ * segment taken as the entry of its directory equal to it ignoring case,
34
+ * until one has none, which is kept as given with all after it (a file to
35
+ * be made keeps its name). Where two entries or more are equal ignoring
36
+ * case, which one is meant is not guessed: `path` comes back unchanged.
37
+ * Each call lists the directories it needs afresh, as they change; one
38
+ * whose path is there costs one lstat.
39
+ */
40
+ export function resolveCase(path: string, caseSensitive = CASE_SENSITIVE): string {
41
+ if (!caseSensitive || !isAbsolute(path) || exists(path)) {
42
+ return path;
43
+ }
44
+
45
+ const root = parse(path).root;
46
+ const segments = path.slice(root.length).split(sep);
47
+ // Joined as given, not normalized: ".." is the file system's to follow, through links as today.
48
+ const at = (count: number, from: string[]) => root + from.slice(0, count).join(sep);
49
+ let found = segments.length - 1;
50
+ while (found > 0 && !exists(at(found, segments))) {
51
+ found--;
52
+ }
53
+
54
+ const resolved = segments.slice();
55
+ for (let i = found; i < segments.length; i++) {
56
+ const segment = segments[i];
57
+ if (segment === "" || segment === "." || segment === "..") {
58
+ continue;
59
+ }
60
+
61
+ const directory = at(i, resolved);
62
+ let names: string[];
63
+ try {
64
+ names = readdirSync(directory);
65
+ } catch {
66
+ break;
67
+ }
68
+
69
+ // In a directory resolved by case, a segment after it may be there exactly.
70
+ if (names.includes(segment)) {
71
+ continue;
72
+ }
73
+
74
+ const wanted = fold(segment);
75
+ const matches = names.filter((name) => fold(name) === wanted);
76
+ if (matches.length === 0) {
77
+ break;
78
+ }
79
+
80
+ if (matches.length > 1) {
81
+ const key = `${directory}${sep}${wanted}`;
82
+ if (!told.has(key)) {
83
+ told.add(key);
84
+ console.error(
85
+ `swf2es: ${directory} holds ${matches.join(", ")}, which differ only in case; ` +
86
+ `${segment} is taken as named, not as any of them.`,
87
+ );
88
+ }
89
+
90
+ return path;
91
+ }
92
+
93
+ resolved[i] = matches[0];
94
+ }
95
+
96
+ return root + resolved.join(sep);
97
+ }
@@ -1,8 +1,10 @@
1
- // One page's flash.net.Socket connections, made with node:net: what the
2
- // socket bridge (sockets.ts) holds for each page, apart from Electron so
3
- // that node runs it in the tests (tests/desktop/connections.test.ts).
1
+ // One page's flash.net.Socket connections, made with node:net, or through
2
+ // the proxy (--proxy, proxy.ts): what the socket bridge (sockets.ts) holds
3
+ // for each page, apart from Electron so that node runs it in the tests
4
+ // (tests/desktop/connections.test.ts).
4
5
  import { connect, type Socket } from "node:net";
5
6
  import type { SocketEvent } from "../shared/api.js";
7
+ import { connectThrough, type ProxyConfig, type ProxyError } from "./proxy.ts";
6
8
 
7
9
  /** As many as a page may hold open at once; past it a connection is refused. */
8
10
  const MAX_OPEN = 64;
@@ -30,17 +32,30 @@ export function validEndpoint(host: unknown, port: unknown): host is string {
30
32
  );
31
33
  }
32
34
 
35
+ export interface ConnectionOptions {
36
+ /** What every connection goes through; none by default. */
37
+ proxy?: ProxyConfig | null;
38
+ /** Told why a connection through the proxy did not come about, for stderr. */
39
+ warn?: (message: string) => void;
40
+ }
41
+
33
42
  export class Connections {
34
43
  private readonly sockets = new Map<number, Socket>();
44
+ /** Connections still being made through the proxy, each stopped by its controller. */
45
+ private readonly opening = new Map<number, AbortController>();
35
46
  private readonly tell: (id: number, event: SocketEvent) => void;
47
+ private readonly proxy: ProxyConfig | null;
48
+ private readonly warn: (message: string) => void;
36
49
 
37
50
  /** `tell` carries each connection's events to its page. */
38
- constructor(tell: (id: number, event: SocketEvent) => void) {
51
+ constructor(tell: (id: number, event: SocketEvent) => void, options: ConnectionOptions = {}) {
39
52
  this.tell = tell;
53
+ this.proxy = options.proxy ?? null;
54
+ this.warn = options.warn ?? (() => {});
40
55
  }
41
56
 
42
57
  get size(): number {
43
- return this.sockets.size;
58
+ return this.sockets.size + this.opening.size;
44
59
  }
45
60
 
46
61
  /** Counts closeAll's: a connection decided on before one belongs to a page that is gone. */
@@ -51,13 +66,23 @@ export class Connections {
51
66
  * was pinned (a remote SWF's socket policy came from there); a refusal is an error, then a close.
52
67
  */
53
68
  connect(id: number, host: unknown, port: unknown, address?: string): void {
54
- if (!validEndpoint(host, port) || this.sockets.has(id) || this.sockets.size >= MAX_OPEN) {
69
+ if (
70
+ !validEndpoint(host, port) ||
71
+ this.sockets.has(id) ||
72
+ this.opening.has(id) ||
73
+ this.size >= MAX_OPEN
74
+ ) {
55
75
  this.refuse(id);
56
76
  return;
57
77
  }
58
78
 
59
- const socket = connect({ host: address ?? host, port: port as number });
60
- this.sockets.set(id, socket);
79
+ const target = address ?? host;
80
+ if (this.proxy) {
81
+ this.connectThrough(this.proxy, id, target, port as number);
82
+ return;
83
+ }
84
+
85
+ const socket = connect({ host: target, port: port as number });
61
86
  socket.on("connect", () =>
62
87
  this.tell(id, {
63
88
  type: "open",
@@ -67,6 +92,49 @@ export class Connections {
67
92
  remotePort: socket.remotePort ?? 0,
68
93
  }),
69
94
  );
95
+ this.attach(id, socket);
96
+ }
97
+
98
+ /**
99
+ * Connect `id` through `proxy`, by the address where one was pinned, else
100
+ * by name for the proxy to resolve. Its peer is the target: the proxy's
101
+ * address is no business of the SWF's. A proxy that fails is a refusal,
102
+ * said with why.
103
+ */
104
+ private connectThrough(proxy: ProxyConfig, id: number, target: string, port: number): void {
105
+ const opening = new AbortController();
106
+ this.opening.set(id, opening);
107
+ connectThrough(proxy, target, port, { signal: opening.signal }).then(
108
+ (socket) => {
109
+ if (this.opening.get(id) !== opening) {
110
+ socket.destroy();
111
+ return;
112
+ }
113
+
114
+ this.opening.delete(id);
115
+ this.attach(id, socket);
116
+ this.tell(id, {
117
+ type: "open",
118
+ localAddress: socket.localAddress ?? "",
119
+ localPort: socket.localPort ?? 0,
120
+ remoteAddress: target,
121
+ remotePort: port,
122
+ });
123
+ },
124
+ (error: ProxyError) => {
125
+ if (this.opening.get(id) !== opening) {
126
+ return;
127
+ }
128
+
129
+ this.opening.delete(id);
130
+ this.warn(`no socket to ${target}:${port}: ${error.message}`);
131
+ this.refuse(id);
132
+ },
133
+ );
134
+ }
135
+
136
+ private attach(id: number, socket: Socket): void {
137
+ this.sockets.set(id, socket);
70
138
  socket.on("data", (bytes) => this.tell(id, { type: "data", bytes: new Uint8Array(bytes) }));
71
139
  socket.on("error", () => this.tell(id, { type: "error", message: SOCKET_ERROR }));
72
140
  socket.on("close", () => {
@@ -105,6 +173,15 @@ export class Connections {
105
173
  }
106
174
 
107
175
  close(id: number): void {
176
+ const opening = this.opening.get(id);
177
+ if (opening) {
178
+ // Closed before the proxy made it: closed, as a socket destroyed before it connects.
179
+ this.opening.delete(id);
180
+ opening.abort();
181
+ this.tell(id, { type: "close" });
182
+ return;
183
+ }
184
+
108
185
  this.sockets.get(id)?.destroy();
109
186
  }
110
187
 
@@ -119,7 +196,12 @@ export class Connections {
119
196
  socket.destroy();
120
197
  }
121
198
 
199
+ for (const opening of this.opening.values()) {
200
+ opening.abort();
201
+ }
202
+
122
203
  this.sockets.clear();
204
+ this.opening.clear();
123
205
  this.generation++;
124
206
  }
125
207
  }