@digitaldefiance/node-express-suite 3.12.12 → 3.12.15
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/README.md +59 -0
- package/package.json +6 -2
- package/src/application.d.ts +1 -0
- package/src/application.d.ts.map +1 -1
- package/src/application.js +12 -1
- package/src/application.js.map +1 -1
- package/src/environment.d.ts +5 -1
- package/src/environment.d.ts.map +1 -1
- package/src/environment.js +31 -0
- package/src/environment.js.map +1 -1
- package/src/greenlock-manager.d.ts +56 -0
- package/src/greenlock-manager.d.ts.map +1 -0
- package/src/greenlock-manager.js +149 -0
- package/src/greenlock-manager.js.map +1 -0
- package/src/index.d.ts +2 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +4 -1
- package/src/index.js.map +1 -1
- package/src/interfaces/environment.d.ts +19 -0
- package/src/interfaces/environment.d.ts.map +1 -1
- package/src/interfaces/index.d.ts +1 -0
- package/src/interfaces/index.d.ts.map +1 -1
- package/src/interfaces/index.js +1 -0
- package/src/interfaces/index.js.map +1 -1
- package/src/interfaces/network/index.d.ts +3 -0
- package/src/interfaces/network/index.d.ts.map +1 -0
- package/src/interfaces/network/index.js +6 -0
- package/src/interfaces/network/index.js.map +1 -0
- package/src/interfaces/network/upnpService.d.ts +86 -0
- package/src/interfaces/network/upnpService.d.ts.map +1 -0
- package/src/interfaces/network/upnpService.js +3 -0
- package/src/interfaces/network/upnpService.js.map +1 -0
- package/src/interfaces/network/upnpTypes.d.ts +120 -0
- package/src/interfaces/network/upnpTypes.d.ts.map +1 -0
- package/src/interfaces/network/upnpTypes.js +57 -0
- package/src/interfaces/network/upnpTypes.js.map +1 -0
- package/src/plugins/index.d.ts +1 -0
- package/src/plugins/index.d.ts.map +1 -1
- package/src/plugins/index.js +1 -0
- package/src/plugins/index.js.map +1 -1
- package/src/plugins/upnp.d.ts +129 -0
- package/src/plugins/upnp.d.ts.map +1 -0
- package/src/plugins/upnp.js +158 -0
- package/src/plugins/upnp.js.map +1 -0
- package/src/services/index.d.ts +3 -0
- package/src/services/index.d.ts.map +1 -1
- package/src/services/index.js +3 -0
- package/src/services/index.js.map +1 -1
- package/src/services/upnp-config.d.ts +131 -0
- package/src/services/upnp-config.d.ts.map +1 -0
- package/src/services/upnp-config.js +225 -0
- package/src/services/upnp-config.js.map +1 -0
- package/src/services/upnp-manager.d.ts +211 -0
- package/src/services/upnp-manager.d.ts.map +1 -0
- package/src/services/upnp-manager.js +447 -0
- package/src/services/upnp-manager.js.map +1 -0
- package/src/services/upnp.d.ts +241 -0
- package/src/services/upnp.d.ts.map +1 -0
- package/src/services/upnp.js +415 -0
- package/src/services/upnp.js.map +1 -0
- package/src/utils.d.ts +13 -0
- package/src/utils.d.ts.map +1 -1
- package/src/utils.js +26 -0
- package/src/utils.js.map +1 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UPnP Port Mapping Service.
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic port forwarding via UPnP/NAT-PMP protocols,
|
|
5
|
+
* enabling servers behind NAT routers to be reachable from the internet.
|
|
6
|
+
* Uses nat-upnp as the primary client with retry logic and exponential
|
|
7
|
+
* backoff for resilience against slow or unreliable routers.
|
|
8
|
+
*
|
|
9
|
+
* Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10
|
|
10
|
+
*/
|
|
11
|
+
import { IUpnpService } from '../interfaces/network/upnpService';
|
|
12
|
+
import { IUpnpConfig, IUpnpMapping, PortMappingProtocol } from '../interfaces/network/upnpTypes';
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when a port number is outside the valid range (1-65535).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* try {
|
|
19
|
+
* UpnpService.validatePort(70000);
|
|
20
|
+
* } catch (err) {
|
|
21
|
+
* if (err instanceof PortRangeError) {
|
|
22
|
+
* console.error(err.message); // "Port 70000 is outside the valid range (1-65535)"
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class PortRangeError extends Error {
|
|
28
|
+
constructor(port: number);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Error thrown when UPnP operations fail after all retry attempts.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* try {
|
|
36
|
+
* await service.getExternalIp();
|
|
37
|
+
* } catch (err) {
|
|
38
|
+
* if (err instanceof UpnpOperationError) {
|
|
39
|
+
* console.error(`Operation failed: ${err.message}`);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class UpnpOperationError extends Error {
|
|
45
|
+
constructor(operation: string, cause?: string);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Error thrown when the UPnP service has been closed and an operation is attempted.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const service = new UpnpService();
|
|
53
|
+
* await service.close();
|
|
54
|
+
*
|
|
55
|
+
* try {
|
|
56
|
+
* await service.getExternalIp(); // throws UpnpServiceClosedError
|
|
57
|
+
* } catch (err) {
|
|
58
|
+
* if (err instanceof UpnpServiceClosedError) {
|
|
59
|
+
* console.error('Service already closed');
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare class UpnpServiceClosedError extends Error {
|
|
65
|
+
constructor();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* UPnP port mapping service implementation.
|
|
69
|
+
*
|
|
70
|
+
* Manages port mappings on a NAT router via the UPnP protocol, with
|
|
71
|
+
* support for external IP discovery, mapping lifecycle management,
|
|
72
|
+
* and retry logic with exponential backoff.
|
|
73
|
+
*
|
|
74
|
+
* **Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10**
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const service = new UpnpService();
|
|
79
|
+
*
|
|
80
|
+
* const externalIp = await service.getExternalIp();
|
|
81
|
+
* await service.createPortMapping({
|
|
82
|
+
* public: 3000,
|
|
83
|
+
* private: 3000,
|
|
84
|
+
* protocol: 'tcp',
|
|
85
|
+
* description: 'Express App HTTP',
|
|
86
|
+
* ttl: 3600,
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // On shutdown
|
|
90
|
+
* await service.close();
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare class UpnpService implements IUpnpService {
|
|
94
|
+
/** The nat-upnp client instance */
|
|
95
|
+
private client;
|
|
96
|
+
/** Service configuration */
|
|
97
|
+
private readonly config;
|
|
98
|
+
/** Active port mappings tracked in memory (keyed by "port:protocol") */
|
|
99
|
+
private readonly activeMappings;
|
|
100
|
+
/** Cached external IP address */
|
|
101
|
+
private cachedExternalIp;
|
|
102
|
+
/** Timestamp when the external IP was last fetched */
|
|
103
|
+
private ipCacheTimestamp;
|
|
104
|
+
/** TTL for the external IP cache in milliseconds */
|
|
105
|
+
private readonly ipCacheTtlMs;
|
|
106
|
+
/** Whether the service has been closed */
|
|
107
|
+
private closed;
|
|
108
|
+
/**
|
|
109
|
+
* Create a new UpnpService.
|
|
110
|
+
*
|
|
111
|
+
* **Validates: Requirement 2.1** — Accepts partial config and merges with defaults
|
|
112
|
+
*
|
|
113
|
+
* @param config - UPnP configuration (uses defaults for omitted fields)
|
|
114
|
+
* @param ipCacheTtlMs - External IP cache TTL in milliseconds (default 5 minutes)
|
|
115
|
+
*/
|
|
116
|
+
constructor(config?: Partial<IUpnpConfig>, ipCacheTtlMs?: number);
|
|
117
|
+
/**
|
|
118
|
+
* Query the router for the external (public) IP address.
|
|
119
|
+
* Results are cached for the configured TTL to reduce router queries.
|
|
120
|
+
*
|
|
121
|
+
* **Validates: Requirement 2.8** — Return cached IP or query router and cache result
|
|
122
|
+
*
|
|
123
|
+
* @returns The external IP address as a string
|
|
124
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
125
|
+
* @throws {UpnpOperationError} If the IP cannot be retrieved after retries
|
|
126
|
+
*/
|
|
127
|
+
getExternalIp(): Promise<string>;
|
|
128
|
+
/**
|
|
129
|
+
* Create a port mapping on the router.
|
|
130
|
+
*
|
|
131
|
+
* **Validates: Requirements 2.2, 2.3** — Validate ports and create mapping with tracking
|
|
132
|
+
*
|
|
133
|
+
* @param mapping - The port mapping configuration to create
|
|
134
|
+
* @throws {PortRangeError} If any port is outside 1-65535
|
|
135
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
136
|
+
* @throws {UpnpOperationError} If the mapping cannot be created after retries
|
|
137
|
+
*/
|
|
138
|
+
createPortMapping(mapping: IUpnpMapping): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Remove a specific port mapping from the router.
|
|
141
|
+
*
|
|
142
|
+
* **Validates: Requirement 2.4** — Remove mapping from router and in-memory tracking
|
|
143
|
+
*
|
|
144
|
+
* @param publicPort - The external port number to unmap
|
|
145
|
+
* @param protocol - The transport protocol of the mapping to remove
|
|
146
|
+
* @throws {PortRangeError} If the port is outside 1-65535
|
|
147
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
148
|
+
* @throws {UpnpOperationError} If the mapping cannot be removed after retries
|
|
149
|
+
*/
|
|
150
|
+
removePortMapping(publicPort: number, protocol: PortMappingProtocol): Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Remove all port mappings created by this service.
|
|
153
|
+
*
|
|
154
|
+
* **Validates: Requirement 2.9** — Remove all active mappings on close
|
|
155
|
+
*
|
|
156
|
+
* Attempts to remove each mapping individually. Failures on individual
|
|
157
|
+
* mappings are logged but do not prevent removal of remaining mappings.
|
|
158
|
+
*/
|
|
159
|
+
removeAllMappings(): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Get all active port mappings managed by this service.
|
|
162
|
+
*
|
|
163
|
+
* **Validates: Requirement 2.5** — Return all mappings tracked in memory
|
|
164
|
+
*
|
|
165
|
+
* @returns Array of active port mappings
|
|
166
|
+
*/
|
|
167
|
+
getMappings(): Promise<IUpnpMapping[]>;
|
|
168
|
+
/**
|
|
169
|
+
* Close the UPnP client and release resources.
|
|
170
|
+
* Removes all active mappings before closing.
|
|
171
|
+
*
|
|
172
|
+
* **Validates: Requirement 2.9** — Remove all mappings, close client, reject subsequent ops
|
|
173
|
+
*
|
|
174
|
+
* @throws {UpnpServiceClosedError} If the service has already been closed
|
|
175
|
+
*/
|
|
176
|
+
close(): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Validate that a port number is within the valid range (1-65535).
|
|
179
|
+
*
|
|
180
|
+
* @param port - The port number to validate
|
|
181
|
+
* @throws {PortRangeError} If the port is outside the valid range
|
|
182
|
+
*/
|
|
183
|
+
static validatePort(port: number): void;
|
|
184
|
+
/**
|
|
185
|
+
* Generate a unique key for a mapping based on port and protocol.
|
|
186
|
+
*
|
|
187
|
+
* @param port - The public port number
|
|
188
|
+
* @param protocol - The transport protocol
|
|
189
|
+
* @returns A string key in the format "port:protocol"
|
|
190
|
+
*/
|
|
191
|
+
static mappingKey(port: number, protocol: PortMappingProtocol): string;
|
|
192
|
+
/**
|
|
193
|
+
* Ensure the service has not been closed.
|
|
194
|
+
*
|
|
195
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
196
|
+
*/
|
|
197
|
+
private ensureNotClosed;
|
|
198
|
+
/**
|
|
199
|
+
* Check whether the cached external IP has expired.
|
|
200
|
+
*
|
|
201
|
+
* @returns true if the cache has expired or was never set
|
|
202
|
+
*/
|
|
203
|
+
private isIpCacheExpired;
|
|
204
|
+
/**
|
|
205
|
+
* Execute an operation with retry logic and exponential backoff.
|
|
206
|
+
*
|
|
207
|
+
* **Validates: Requirements 2.6, 2.7** — Retry with exponential backoff, throw UpnpOperationError on exhaustion
|
|
208
|
+
*
|
|
209
|
+
* @param operationName - Name of the operation (for error messages)
|
|
210
|
+
* @param operation - The async operation to execute
|
|
211
|
+
* @returns The result of the operation
|
|
212
|
+
* @throws {UpnpOperationError} If all retry attempts are exhausted
|
|
213
|
+
*/
|
|
214
|
+
private withRetry;
|
|
215
|
+
/**
|
|
216
|
+
* Promisified wrapper around the nat-upnp externalIp callback API.
|
|
217
|
+
*
|
|
218
|
+
* @returns The external IP address
|
|
219
|
+
*/
|
|
220
|
+
private promisifiedExternalIp;
|
|
221
|
+
/**
|
|
222
|
+
* Promisified wrapper around the nat-upnp portMapping callback API.
|
|
223
|
+
*
|
|
224
|
+
* @param options - Port mapping options
|
|
225
|
+
*/
|
|
226
|
+
private promisifiedPortMapping;
|
|
227
|
+
/**
|
|
228
|
+
* Promisified wrapper around the nat-upnp portUnmapping callback API.
|
|
229
|
+
*
|
|
230
|
+
* @param options - Port unmapping options
|
|
231
|
+
*/
|
|
232
|
+
private promisifiedPortUnmapping;
|
|
233
|
+
/**
|
|
234
|
+
* Sleep for the specified duration.
|
|
235
|
+
*
|
|
236
|
+
* @param ms - Duration in milliseconds
|
|
237
|
+
* @returns A promise that resolves after the specified duration
|
|
238
|
+
*/
|
|
239
|
+
static sleep(ms: number): Promise<void>;
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=upnp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upnp.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/services/upnp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EAEpB,MAAM,iCAAiC,CAAC;AAezC;;;;;;;;;;;;;GAaG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;CAO9C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAKhD;AAID;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,mCAAmC;IACnC,OAAO,CAAC,MAAM,CAAiB;IAE/B,4BAA4B;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAE/C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IAEvE,iCAAiC;IACjC,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,sDAAsD;IACtD,OAAO,CAAC,gBAAgB,CAAK;IAE7B,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,0CAA0C;IAC1C,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;;;;OAOG;gBAED,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,EACjC,YAAY,GAAE,MAAgC;IAShD;;;;;;;;;OASG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBtC;;;;;;;;;OASG;IACG,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7D;;;;;;;;;;OAUG;IACG,iBAAiB,CACrB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAgBhB;;;;;;;OAOG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BxC;;;;;;OAMG;IACG,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAK5C;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB5B;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMvC;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,MAAM;IAMtE;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAMvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;;;;;;;OASG;YACW,SAAS;IA0BvB;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAc9B;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAchC;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGxC"}
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* UPnP Port Mapping Service.
|
|
4
|
+
*
|
|
5
|
+
* Provides automatic port forwarding via UPnP/NAT-PMP protocols,
|
|
6
|
+
* enabling servers behind NAT routers to be reachable from the internet.
|
|
7
|
+
* Uses nat-upnp as the primary client with retry logic and exponential
|
|
8
|
+
* backoff for resilience against slow or unreliable routers.
|
|
9
|
+
*
|
|
10
|
+
* Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.UpnpService = exports.UpnpServiceClosedError = exports.UpnpOperationError = exports.PortRangeError = void 0;
|
|
14
|
+
const tslib_1 = require("tslib");
|
|
15
|
+
const natUpnp = tslib_1.__importStar(require("nat-upnp"));
|
|
16
|
+
const upnpTypes_1 = require("../interfaces/network/upnpTypes");
|
|
17
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
18
|
+
/** Minimum valid port number */
|
|
19
|
+
const MIN_PORT = 1;
|
|
20
|
+
/** Maximum valid port number */
|
|
21
|
+
const MAX_PORT = 65535;
|
|
22
|
+
/** Default external IP cache TTL in milliseconds (5 minutes) */
|
|
23
|
+
const DEFAULT_IP_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
24
|
+
// ─── Error classes ──────────────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when a port number is outside the valid range (1-65535).
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* try {
|
|
31
|
+
* UpnpService.validatePort(70000);
|
|
32
|
+
* } catch (err) {
|
|
33
|
+
* if (err instanceof PortRangeError) {
|
|
34
|
+
* console.error(err.message); // "Port 70000 is outside the valid range (1-65535)"
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
class PortRangeError extends Error {
|
|
40
|
+
constructor(port) {
|
|
41
|
+
super(`Port ${port} is outside the valid range (${MIN_PORT}-${MAX_PORT})`);
|
|
42
|
+
this.name = 'PortRangeError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.PortRangeError = PortRangeError;
|
|
46
|
+
/**
|
|
47
|
+
* Error thrown when UPnP operations fail after all retry attempts.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* try {
|
|
52
|
+
* await service.getExternalIp();
|
|
53
|
+
* } catch (err) {
|
|
54
|
+
* if (err instanceof UpnpOperationError) {
|
|
55
|
+
* console.error(`Operation failed: ${err.message}`);
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
class UpnpOperationError extends Error {
|
|
61
|
+
constructor(operation, cause) {
|
|
62
|
+
const message = cause
|
|
63
|
+
? `UPnP ${operation} failed: ${cause}`
|
|
64
|
+
: `UPnP ${operation} failed`;
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = 'UpnpOperationError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.UpnpOperationError = UpnpOperationError;
|
|
70
|
+
/**
|
|
71
|
+
* Error thrown when the UPnP service has been closed and an operation is attempted.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const service = new UpnpService();
|
|
76
|
+
* await service.close();
|
|
77
|
+
*
|
|
78
|
+
* try {
|
|
79
|
+
* await service.getExternalIp(); // throws UpnpServiceClosedError
|
|
80
|
+
* } catch (err) {
|
|
81
|
+
* if (err instanceof UpnpServiceClosedError) {
|
|
82
|
+
* console.error('Service already closed');
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
class UpnpServiceClosedError extends Error {
|
|
88
|
+
constructor() {
|
|
89
|
+
super('UPnP service has been closed');
|
|
90
|
+
this.name = 'UpnpServiceClosedError';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.UpnpServiceClosedError = UpnpServiceClosedError;
|
|
94
|
+
// ─── Service ────────────────────────────────────────────────────────────────
|
|
95
|
+
/**
|
|
96
|
+
* UPnP port mapping service implementation.
|
|
97
|
+
*
|
|
98
|
+
* Manages port mappings on a NAT router via the UPnP protocol, with
|
|
99
|
+
* support for external IP discovery, mapping lifecycle management,
|
|
100
|
+
* and retry logic with exponential backoff.
|
|
101
|
+
*
|
|
102
|
+
* **Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10**
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const service = new UpnpService();
|
|
107
|
+
*
|
|
108
|
+
* const externalIp = await service.getExternalIp();
|
|
109
|
+
* await service.createPortMapping({
|
|
110
|
+
* public: 3000,
|
|
111
|
+
* private: 3000,
|
|
112
|
+
* protocol: 'tcp',
|
|
113
|
+
* description: 'Express App HTTP',
|
|
114
|
+
* ttl: 3600,
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* // On shutdown
|
|
118
|
+
* await service.close();
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
class UpnpService {
|
|
122
|
+
/** The nat-upnp client instance */
|
|
123
|
+
client;
|
|
124
|
+
/** Service configuration */
|
|
125
|
+
config;
|
|
126
|
+
/** Active port mappings tracked in memory (keyed by "port:protocol") */
|
|
127
|
+
activeMappings = new Map();
|
|
128
|
+
/** Cached external IP address */
|
|
129
|
+
cachedExternalIp = null;
|
|
130
|
+
/** Timestamp when the external IP was last fetched */
|
|
131
|
+
ipCacheTimestamp = 0;
|
|
132
|
+
/** TTL for the external IP cache in milliseconds */
|
|
133
|
+
ipCacheTtlMs;
|
|
134
|
+
/** Whether the service has been closed */
|
|
135
|
+
closed = false;
|
|
136
|
+
/**
|
|
137
|
+
* Create a new UpnpService.
|
|
138
|
+
*
|
|
139
|
+
* **Validates: Requirement 2.1** — Accepts partial config and merges with defaults
|
|
140
|
+
*
|
|
141
|
+
* @param config - UPnP configuration (uses defaults for omitted fields)
|
|
142
|
+
* @param ipCacheTtlMs - External IP cache TTL in milliseconds (default 5 minutes)
|
|
143
|
+
*/
|
|
144
|
+
constructor(config = {}, ipCacheTtlMs = DEFAULT_IP_CACHE_TTL_MS) {
|
|
145
|
+
this.config = { ...upnpTypes_1.UPNP_CONFIG_DEFAULTS, ...config };
|
|
146
|
+
this.ipCacheTtlMs = ipCacheTtlMs;
|
|
147
|
+
this.client = natUpnp.createClient();
|
|
148
|
+
}
|
|
149
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
150
|
+
/**
|
|
151
|
+
* Query the router for the external (public) IP address.
|
|
152
|
+
* Results are cached for the configured TTL to reduce router queries.
|
|
153
|
+
*
|
|
154
|
+
* **Validates: Requirement 2.8** — Return cached IP or query router and cache result
|
|
155
|
+
*
|
|
156
|
+
* @returns The external IP address as a string
|
|
157
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
158
|
+
* @throws {UpnpOperationError} If the IP cannot be retrieved after retries
|
|
159
|
+
*/
|
|
160
|
+
async getExternalIp() {
|
|
161
|
+
this.ensureNotClosed();
|
|
162
|
+
// Return cached IP if still valid
|
|
163
|
+
if (this.cachedExternalIp && !this.isIpCacheExpired()) {
|
|
164
|
+
return this.cachedExternalIp;
|
|
165
|
+
}
|
|
166
|
+
const ip = await this.withRetry('getExternalIp', () => this.promisifiedExternalIp());
|
|
167
|
+
this.cachedExternalIp = ip;
|
|
168
|
+
this.ipCacheTimestamp = Date.now();
|
|
169
|
+
return ip;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Create a port mapping on the router.
|
|
173
|
+
*
|
|
174
|
+
* **Validates: Requirements 2.2, 2.3** — Validate ports and create mapping with tracking
|
|
175
|
+
*
|
|
176
|
+
* @param mapping - The port mapping configuration to create
|
|
177
|
+
* @throws {PortRangeError} If any port is outside 1-65535
|
|
178
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
179
|
+
* @throws {UpnpOperationError} If the mapping cannot be created after retries
|
|
180
|
+
*/
|
|
181
|
+
async createPortMapping(mapping) {
|
|
182
|
+
this.ensureNotClosed();
|
|
183
|
+
UpnpService.validatePort(mapping.public);
|
|
184
|
+
UpnpService.validatePort(mapping.private);
|
|
185
|
+
await this.withRetry('createPortMapping', () => this.promisifiedPortMapping({
|
|
186
|
+
public: mapping.public,
|
|
187
|
+
private: mapping.private,
|
|
188
|
+
protocol: mapping.protocol,
|
|
189
|
+
description: mapping.description,
|
|
190
|
+
ttl: mapping.ttl,
|
|
191
|
+
}));
|
|
192
|
+
// Track the mapping in memory
|
|
193
|
+
const key = UpnpService.mappingKey(mapping.public, mapping.protocol);
|
|
194
|
+
this.activeMappings.set(key, { ...mapping });
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Remove a specific port mapping from the router.
|
|
198
|
+
*
|
|
199
|
+
* **Validates: Requirement 2.4** — Remove mapping from router and in-memory tracking
|
|
200
|
+
*
|
|
201
|
+
* @param publicPort - The external port number to unmap
|
|
202
|
+
* @param protocol - The transport protocol of the mapping to remove
|
|
203
|
+
* @throws {PortRangeError} If the port is outside 1-65535
|
|
204
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
205
|
+
* @throws {UpnpOperationError} If the mapping cannot be removed after retries
|
|
206
|
+
*/
|
|
207
|
+
async removePortMapping(publicPort, protocol) {
|
|
208
|
+
this.ensureNotClosed();
|
|
209
|
+
UpnpService.validatePort(publicPort);
|
|
210
|
+
await this.withRetry('removePortMapping', () => this.promisifiedPortUnmapping({
|
|
211
|
+
public: publicPort,
|
|
212
|
+
protocol,
|
|
213
|
+
}));
|
|
214
|
+
// Remove from tracked mappings
|
|
215
|
+
const key = UpnpService.mappingKey(publicPort, protocol);
|
|
216
|
+
this.activeMappings.delete(key);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Remove all port mappings created by this service.
|
|
220
|
+
*
|
|
221
|
+
* **Validates: Requirement 2.9** — Remove all active mappings on close
|
|
222
|
+
*
|
|
223
|
+
* Attempts to remove each mapping individually. Failures on individual
|
|
224
|
+
* mappings are logged but do not prevent removal of remaining mappings.
|
|
225
|
+
*/
|
|
226
|
+
async removeAllMappings() {
|
|
227
|
+
this.ensureNotClosed();
|
|
228
|
+
const mappings = Array.from(this.activeMappings.values());
|
|
229
|
+
const errors = [];
|
|
230
|
+
for (const mapping of mappings) {
|
|
231
|
+
try {
|
|
232
|
+
await this.removePortMapping(mapping.public, mapping.protocol);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
errors.push({
|
|
236
|
+
mapping,
|
|
237
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Clear all tracked mappings even if some removals failed
|
|
242
|
+
this.activeMappings.clear();
|
|
243
|
+
if (errors.length > 0) {
|
|
244
|
+
const details = errors
|
|
245
|
+
.map((e) => `${e.mapping.public}/${e.mapping.protocol}: ${e.error.message}`)
|
|
246
|
+
.join('; ');
|
|
247
|
+
throw new UpnpOperationError('removeAllMappings', details);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get all active port mappings managed by this service.
|
|
252
|
+
*
|
|
253
|
+
* **Validates: Requirement 2.5** — Return all mappings tracked in memory
|
|
254
|
+
*
|
|
255
|
+
* @returns Array of active port mappings
|
|
256
|
+
*/
|
|
257
|
+
async getMappings() {
|
|
258
|
+
this.ensureNotClosed();
|
|
259
|
+
return Array.from(this.activeMappings.values());
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Close the UPnP client and release resources.
|
|
263
|
+
* Removes all active mappings before closing.
|
|
264
|
+
*
|
|
265
|
+
* **Validates: Requirement 2.9** — Remove all mappings, close client, reject subsequent ops
|
|
266
|
+
*
|
|
267
|
+
* @throws {UpnpServiceClosedError} If the service has already been closed
|
|
268
|
+
*/
|
|
269
|
+
async close() {
|
|
270
|
+
this.ensureNotClosed();
|
|
271
|
+
// Best-effort removal of all mappings before closing
|
|
272
|
+
try {
|
|
273
|
+
await this.removeAllMappings();
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
// Swallow errors during cleanup — we're shutting down
|
|
277
|
+
}
|
|
278
|
+
this.client.close();
|
|
279
|
+
this.closed = true;
|
|
280
|
+
this.cachedExternalIp = null;
|
|
281
|
+
}
|
|
282
|
+
// ─── Static helpers ─────────────────────────────────────────────────────
|
|
283
|
+
/**
|
|
284
|
+
* Validate that a port number is within the valid range (1-65535).
|
|
285
|
+
*
|
|
286
|
+
* @param port - The port number to validate
|
|
287
|
+
* @throws {PortRangeError} If the port is outside the valid range
|
|
288
|
+
*/
|
|
289
|
+
static validatePort(port) {
|
|
290
|
+
if (!Number.isInteger(port) || port < MIN_PORT || port > MAX_PORT) {
|
|
291
|
+
throw new PortRangeError(port);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Generate a unique key for a mapping based on port and protocol.
|
|
296
|
+
*
|
|
297
|
+
* @param port - The public port number
|
|
298
|
+
* @param protocol - The transport protocol
|
|
299
|
+
* @returns A string key in the format "port:protocol"
|
|
300
|
+
*/
|
|
301
|
+
static mappingKey(port, protocol) {
|
|
302
|
+
return `${port}:${protocol}`;
|
|
303
|
+
}
|
|
304
|
+
// ─── Private helpers ────────────────────────────────────────────────────
|
|
305
|
+
/**
|
|
306
|
+
* Ensure the service has not been closed.
|
|
307
|
+
*
|
|
308
|
+
* @throws {UpnpServiceClosedError} If the service has been closed
|
|
309
|
+
*/
|
|
310
|
+
ensureNotClosed() {
|
|
311
|
+
if (this.closed) {
|
|
312
|
+
throw new UpnpServiceClosedError();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check whether the cached external IP has expired.
|
|
317
|
+
*
|
|
318
|
+
* @returns true if the cache has expired or was never set
|
|
319
|
+
*/
|
|
320
|
+
isIpCacheExpired() {
|
|
321
|
+
return Date.now() - this.ipCacheTimestamp > this.ipCacheTtlMs;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Execute an operation with retry logic and exponential backoff.
|
|
325
|
+
*
|
|
326
|
+
* **Validates: Requirements 2.6, 2.7** — Retry with exponential backoff, throw UpnpOperationError on exhaustion
|
|
327
|
+
*
|
|
328
|
+
* @param operationName - Name of the operation (for error messages)
|
|
329
|
+
* @param operation - The async operation to execute
|
|
330
|
+
* @returns The result of the operation
|
|
331
|
+
* @throws {UpnpOperationError} If all retry attempts are exhausted
|
|
332
|
+
*/
|
|
333
|
+
async withRetry(operationName, operation) {
|
|
334
|
+
let lastError;
|
|
335
|
+
for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
|
|
336
|
+
try {
|
|
337
|
+
return await operation();
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
341
|
+
// Don't delay after the last attempt
|
|
342
|
+
if (attempt < this.config.retryAttempts) {
|
|
343
|
+
const delay = this.config.retryDelay * Math.pow(2, attempt);
|
|
344
|
+
await UpnpService.sleep(delay);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
throw new UpnpOperationError(operationName, lastError?.message ?? 'unknown error');
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Promisified wrapper around the nat-upnp externalIp callback API.
|
|
352
|
+
*
|
|
353
|
+
* @returns The external IP address
|
|
354
|
+
*/
|
|
355
|
+
promisifiedExternalIp() {
|
|
356
|
+
return new Promise((resolve, reject) => {
|
|
357
|
+
this.client.externalIp((err, ip) => {
|
|
358
|
+
if (err) {
|
|
359
|
+
reject(err);
|
|
360
|
+
}
|
|
361
|
+
else if (ip) {
|
|
362
|
+
resolve(ip);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
reject(new Error('No external IP returned'));
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Promisified wrapper around the nat-upnp portMapping callback API.
|
|
372
|
+
*
|
|
373
|
+
* @param options - Port mapping options
|
|
374
|
+
*/
|
|
375
|
+
promisifiedPortMapping(options) {
|
|
376
|
+
return new Promise((resolve, reject) => {
|
|
377
|
+
this.client.portMapping(options, (err) => {
|
|
378
|
+
if (err) {
|
|
379
|
+
reject(err);
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
resolve();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Promisified wrapper around the nat-upnp portUnmapping callback API.
|
|
389
|
+
*
|
|
390
|
+
* @param options - Port unmapping options
|
|
391
|
+
*/
|
|
392
|
+
promisifiedPortUnmapping(options) {
|
|
393
|
+
return new Promise((resolve, reject) => {
|
|
394
|
+
this.client.portUnmapping(options, (err) => {
|
|
395
|
+
if (err) {
|
|
396
|
+
reject(err);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
resolve();
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Sleep for the specified duration.
|
|
406
|
+
*
|
|
407
|
+
* @param ms - Duration in milliseconds
|
|
408
|
+
* @returns A promise that resolves after the specified duration
|
|
409
|
+
*/
|
|
410
|
+
static sleep(ms) {
|
|
411
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
exports.UpnpService = UpnpService;
|
|
415
|
+
//# sourceMappingURL=upnp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upnp.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-node-express-suite/src/services/upnp.ts"],"names":[],"mappings":"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"}
|
package/src/utils.d.ts
CHANGED
|
@@ -237,4 +237,17 @@ export declare function getLengthEncodingTypeFromValue(value: number): LengthEnc
|
|
|
237
237
|
*/
|
|
238
238
|
export declare function getLengthForLengthType(type: LengthEncodingType): number;
|
|
239
239
|
export declare function parseBackupCodes(user: 'admin' | 'member' | 'system', environment: Record<string, string | undefined>): BackupCode[];
|
|
240
|
+
/**
|
|
241
|
+
* Validates whether a hostname is a valid FQDN or wildcard pattern.
|
|
242
|
+
* @param hostname The hostname string to validate
|
|
243
|
+
* @returns true if the hostname matches either the FQDN or wildcard pattern
|
|
244
|
+
*/
|
|
245
|
+
export declare function isValidHostname(hostname: string): boolean;
|
|
246
|
+
/**
|
|
247
|
+
* Parses a comma-separated string of hostnames into an array.
|
|
248
|
+
* Trims whitespace from each entry and filters out empty strings.
|
|
249
|
+
* @param raw The raw comma-separated hostname string
|
|
250
|
+
* @returns An array of trimmed, non-empty hostname strings
|
|
251
|
+
*/
|
|
252
|
+
export declare function parseHostnames(raw: string): string[];
|
|
240
253
|
//# sourceMappingURL=utils.d.ts.map
|