dsh-mobile 0.3.12 → 0.3.14
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/CHANGELOG.md +11 -0
- package/README.en.md +9 -8
- package/README.md +9 -8
- package/lib/client.js +229 -31
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +50 -28
- package/lib/index.mjs +80 -7
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +9 -1
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.mts
CHANGED
|
@@ -364,6 +364,51 @@ declare class MobileAccessGatewayController {
|
|
|
364
364
|
private enqueue;
|
|
365
365
|
}
|
|
366
366
|
//#endregion
|
|
367
|
+
//#region src/websocket-paths.d.ts
|
|
368
|
+
/** Cap the admin-approved extra WebSocket upgrade paths (exact pathnames). */
|
|
369
|
+
declare const MAX_EXTRA_WEBSOCKET_PATHS = 16;
|
|
370
|
+
declare const MAX_WEBSOCKET_PATH_LENGTH = 256;
|
|
371
|
+
/**
|
|
372
|
+
* Validate one exact pathname for proxying. Query strings are matched at
|
|
373
|
+
* upgrade time, so only the pathname is stored. Rejects anything the
|
|
374
|
+
* gateway cannot match exactly.
|
|
375
|
+
*/
|
|
376
|
+
declare function validateWebSocketPath(value: unknown): string;
|
|
377
|
+
/** Validate a whole replacement list all-or-nothing; duplicates collapse. */
|
|
378
|
+
declare function normalizeWebSocketPaths(value: unknown): string[];
|
|
379
|
+
/** Cap remembered rejected upgrade paths offered for one-click approval. */
|
|
380
|
+
declare const MAX_BLOCKED_UPGRADE_PATHS = 32;
|
|
381
|
+
interface BlockedUpgradePathEntry {
|
|
382
|
+
readonly path: string;
|
|
383
|
+
readonly attempts: number;
|
|
384
|
+
readonly firstSeen: number;
|
|
385
|
+
readonly lastSeen: number;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* In-memory log of rejected third-party upgrade paths, shared by every
|
|
389
|
+
* gateway instance so the approval UI sees attempts on any listener.
|
|
390
|
+
* Bounded and newest-first; a restart clears it (attempts reappear on
|
|
391
|
+
* the next blocked handshake).
|
|
392
|
+
*/
|
|
393
|
+
declare class BlockedUpgradePathLog {
|
|
394
|
+
private readonly entries;
|
|
395
|
+
record(pathname: string): void;
|
|
396
|
+
report(): BlockedUpgradePathEntry[];
|
|
397
|
+
}
|
|
398
|
+
/** File-backed store shared by every gateway instance (LAN and remote). */
|
|
399
|
+
declare class WebSocketPathStore {
|
|
400
|
+
private readonly file;
|
|
401
|
+
private paths;
|
|
402
|
+
private loaded;
|
|
403
|
+
constructor(file: string);
|
|
404
|
+
/** Snapshot for the upgrade check. */
|
|
405
|
+
has(pathname: string): boolean;
|
|
406
|
+
list(): string[];
|
|
407
|
+
load(): Promise<string[]>;
|
|
408
|
+
/** Replace the whole list after validating; persists atomically. */
|
|
409
|
+
replace(paths: readonly string[]): Promise<string[]>;
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
367
412
|
//#region src/extensions.d.ts
|
|
368
413
|
/** Maximum sizes enforced at the local-extension filesystem boundary. */
|
|
369
414
|
declare const EXTENSION_LIMITS: Readonly<{
|
|
@@ -536,6 +581,7 @@ declare class MobileAccessGateway {
|
|
|
536
581
|
private readonly extensions?;
|
|
537
582
|
private readonly upstreamAuthenticatedUrl?;
|
|
538
583
|
private readonly extraWebSocketPaths?;
|
|
584
|
+
private readonly blockedUpgradeLog?;
|
|
539
585
|
readonly access: AccessController;
|
|
540
586
|
private readonly listenerTlsEnabled;
|
|
541
587
|
private readonly tlsEnabled;
|
|
@@ -568,7 +614,7 @@ declare class MobileAccessGateway {
|
|
|
568
614
|
private readonly renewLimiter;
|
|
569
615
|
constructor(config: ResolvedGatewayConfig, store: DeviceStore, extensions?: MobileAccessService | undefined, upstreamAuthenticatedUrl?: string | undefined, extraWebSocketPaths?: {
|
|
570
616
|
has(pathname: string): boolean;
|
|
571
|
-
} | undefined);
|
|
617
|
+
} | undefined, blockedUpgradeLog?: BlockedUpgradePathLog | undefined);
|
|
572
618
|
/** Initialize durable state, validate TLS, and bind the externally reachable listener. */
|
|
573
619
|
start(): Promise<void>;
|
|
574
620
|
private startDiscovery;
|
|
@@ -608,6 +654,8 @@ declare class MobileAccessGateway {
|
|
|
608
654
|
private pollLegacyCustomChanges;
|
|
609
655
|
private openExtensionEventStream;
|
|
610
656
|
private readUpgradeResponse;
|
|
657
|
+
/** Snapshot of rejected upgrade paths for the approval UI (newest first). */
|
|
658
|
+
blockedUpgradePathReport(): BlockedUpgradePathEntry[];
|
|
611
659
|
private handleUpgrade;
|
|
612
660
|
/** Loopback-only DSH WebServer route for opening pairing and managing devices. */
|
|
613
661
|
localAdminRoute(prefix?: string): WebRoute;
|
|
@@ -691,32 +739,6 @@ declare class FrpComponentManager {
|
|
|
691
739
|
private enqueue;
|
|
692
740
|
}
|
|
693
741
|
//#endregion
|
|
694
|
-
//#region src/websocket-paths.d.ts
|
|
695
|
-
/** Cap the admin-approved extra WebSocket upgrade paths (exact pathnames). */
|
|
696
|
-
declare const MAX_EXTRA_WEBSOCKET_PATHS = 16;
|
|
697
|
-
declare const MAX_WEBSOCKET_PATH_LENGTH = 256;
|
|
698
|
-
/**
|
|
699
|
-
* Validate one exact pathname for proxying. Query strings are matched at
|
|
700
|
-
* upgrade time, so only the pathname is stored. Rejects anything the
|
|
701
|
-
* gateway cannot match exactly.
|
|
702
|
-
*/
|
|
703
|
-
declare function validateWebSocketPath(value: unknown): string;
|
|
704
|
-
/** Validate a whole replacement list all-or-nothing; duplicates collapse. */
|
|
705
|
-
declare function normalizeWebSocketPaths(value: unknown): string[];
|
|
706
|
-
/** File-backed store shared by every gateway instance (LAN and remote). */
|
|
707
|
-
declare class WebSocketPathStore {
|
|
708
|
-
private readonly file;
|
|
709
|
-
private paths;
|
|
710
|
-
private loaded;
|
|
711
|
-
constructor(file: string);
|
|
712
|
-
/** Snapshot for the upgrade check. */
|
|
713
|
-
has(pathname: string): boolean;
|
|
714
|
-
list(): string[];
|
|
715
|
-
load(): Promise<string[]>;
|
|
716
|
-
/** Replace the whole list after validating; persists atomically. */
|
|
717
|
-
replace(paths: readonly string[]): Promise<string[]>;
|
|
718
|
-
}
|
|
719
|
-
//#endregion
|
|
720
742
|
//#region src/frp-template.d.ts
|
|
721
743
|
/** Loopback-only HTTP vhost port used between Caddy and frps. */
|
|
722
744
|
declare const FRP_VHOST_HTTP_PORT = 7080;
|
|
@@ -907,5 +929,5 @@ declare const inject: string[];
|
|
|
907
929
|
/** Mount the resident control route and its optional authenticated LAN gateway. */
|
|
908
930
|
declare function apply(ctx: Context, config: PluginConfig): Promise<void>;
|
|
909
931
|
//#endregion
|
|
910
|
-
export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceSnapshot, type DeviceStore, type DeviceSummary, type DisabledTlsConfig, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, type FrpComponentStatus, FrpConfigStore, type FrpConfigurationStatus, FrpController, type FrpControllerOptions, type FrpSettings, type FrpState, type FrpStatus, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, type LocalExtensionManifest, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, type MobileAccessControlState, type MobileAccessControlStore, MobileAccessGateway, MobileAccessGatewayController, type MobileAccessService as MobileAccessRegistry, MobileAccessService, type MobileAccessRuntime, type MobileActionContext, type MobileExtensionClientEntry, type MobileExtensionDefinition, MobileExtensionError, type MobileExtensionManifest, type MobileExtensionStatus, type MobileHostAction, type MobileHostRoute, type MobileRouteRequest, type MobileRouteResponse, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type SessionAuthorization, type StoredDevice, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath };
|
|
932
|
+
export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, type BlockedUpgradePathEntry, BlockedUpgradePathLog, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceSnapshot, type DeviceStore, type DeviceSummary, type DisabledTlsConfig, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, type FrpComponentStatus, FrpConfigStore, type FrpConfigurationStatus, FrpController, type FrpControllerOptions, type FrpSettings, type FrpState, type FrpStatus, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, type LocalExtensionManifest, MAX_BLOCKED_UPGRADE_PATHS, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, type MobileAccessControlState, type MobileAccessControlStore, MobileAccessGateway, MobileAccessGatewayController, type MobileAccessService as MobileAccessRegistry, MobileAccessService, type MobileAccessRuntime, type MobileActionContext, type MobileExtensionClientEntry, type MobileExtensionDefinition, MobileExtensionError, type MobileExtensionManifest, type MobileExtensionStatus, type MobileHostAction, type MobileHostRoute, type MobileRouteRequest, type MobileRouteResponse, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type SessionAuthorization, type StoredDevice, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath };
|
|
911
933
|
//# sourceMappingURL=index.d.mts.map
|
package/lib/index.mjs
CHANGED
|
@@ -2694,6 +2694,7 @@ var MobileAccessGateway = class {
|
|
|
2694
2694
|
extensions;
|
|
2695
2695
|
upstreamAuthenticatedUrl;
|
|
2696
2696
|
extraWebSocketPaths;
|
|
2697
|
+
blockedUpgradeLog;
|
|
2697
2698
|
access;
|
|
2698
2699
|
listenerTlsEnabled;
|
|
2699
2700
|
tlsEnabled;
|
|
@@ -2724,11 +2725,12 @@ var MobileAccessGateway = class {
|
|
|
2724
2725
|
removeSessionListener;
|
|
2725
2726
|
removeExtensionContentListener;
|
|
2726
2727
|
renewLimiter;
|
|
2727
|
-
constructor(config, store, extensions, upstreamAuthenticatedUrl, extraWebSocketPaths) {
|
|
2728
|
+
constructor(config, store, extensions, upstreamAuthenticatedUrl, extraWebSocketPaths, blockedUpgradeLog) {
|
|
2728
2729
|
this.config = config;
|
|
2729
2730
|
this.extensions = extensions;
|
|
2730
2731
|
this.upstreamAuthenticatedUrl = upstreamAuthenticatedUrl;
|
|
2731
2732
|
this.extraWebSocketPaths = extraWebSocketPaths;
|
|
2733
|
+
this.blockedUpgradeLog = blockedUpgradeLog;
|
|
2732
2734
|
this.listenerTlsEnabled = config.tls.mode === "provided";
|
|
2733
2735
|
this.tlsEnabled = config.publicTls;
|
|
2734
2736
|
this.access = new AccessController(store, {
|
|
@@ -3912,12 +3914,19 @@ var MobileAccessGateway = class {
|
|
|
3912
3914
|
upstream.once("close", closed);
|
|
3913
3915
|
});
|
|
3914
3916
|
}
|
|
3917
|
+
/** Snapshot of rejected upgrade paths for the approval UI (newest first). */
|
|
3918
|
+
blockedUpgradePathReport() {
|
|
3919
|
+
return this.blockedUpgradeLog?.report() ?? [];
|
|
3920
|
+
}
|
|
3915
3921
|
async handleUpgrade(request, client, head) {
|
|
3916
3922
|
const target = parseRequestTarget(request.url);
|
|
3917
3923
|
const policy = this.requirePolicy();
|
|
3918
3924
|
assertExternalTrust(request, policy, false);
|
|
3919
3925
|
if (!policy.acceptsOrigin(request.headers.origin)) throw new HttpError(403, "forbidden");
|
|
3920
|
-
if (!(WS_PATHS.has(target.decodedPathname) || (this.extraWebSocketPaths?.has(target.decodedPathname) ?? false)))
|
|
3926
|
+
if (!(WS_PATHS.has(target.decodedPathname) || (this.extraWebSocketPaths?.has(target.decodedPathname) ?? false))) {
|
|
3927
|
+
this.blockedUpgradeLog?.record(target.decodedPathname);
|
|
3928
|
+
throw new HttpError(404, "not_found");
|
|
3929
|
+
}
|
|
3921
3930
|
if (request.method !== "GET" || headerValue(request.headers, "upgrade")?.toLowerCase() !== "websocket" || !hasToken(headerValue(request.headers, "connection"), "upgrade")) throw new HttpError(400, "bad_request");
|
|
3922
3931
|
const key = headerValue(request.headers, "sec-websocket-key");
|
|
3923
3932
|
if (key === void 0 || headerValue(request.headers, "sec-websocket-version") !== "13") throw new HttpError(400, "bad_request");
|
|
@@ -4632,6 +4641,42 @@ function normalizeWebSocketPaths(value) {
|
|
|
4632
4641
|
}
|
|
4633
4642
|
return [...seen];
|
|
4634
4643
|
}
|
|
4644
|
+
/** Cap remembered rejected upgrade paths offered for one-click approval. */
|
|
4645
|
+
const MAX_BLOCKED_UPGRADE_PATHS = 32;
|
|
4646
|
+
/**
|
|
4647
|
+
* In-memory log of rejected third-party upgrade paths, shared by every
|
|
4648
|
+
* gateway instance so the approval UI sees attempts on any listener.
|
|
4649
|
+
* Bounded and newest-first; a restart clears it (attempts reappear on
|
|
4650
|
+
* the next blocked handshake).
|
|
4651
|
+
*/
|
|
4652
|
+
var BlockedUpgradePathLog = class {
|
|
4653
|
+
entries = /* @__PURE__ */ new Map();
|
|
4654
|
+
record(pathname) {
|
|
4655
|
+
const now = Date.now();
|
|
4656
|
+
const stats = this.entries.get(pathname);
|
|
4657
|
+
if (stats === void 0) {
|
|
4658
|
+
if (this.entries.size >= 32) {
|
|
4659
|
+
let oldest;
|
|
4660
|
+
for (const [path, entry] of this.entries) if (oldest === void 0 || entry.lastSeen < (this.entries.get(oldest)?.lastSeen ?? 0)) oldest = path;
|
|
4661
|
+
if (oldest !== void 0) this.entries.delete(oldest);
|
|
4662
|
+
}
|
|
4663
|
+
this.entries.set(pathname, {
|
|
4664
|
+
attempts: 1,
|
|
4665
|
+
firstSeen: now,
|
|
4666
|
+
lastSeen: now
|
|
4667
|
+
});
|
|
4668
|
+
return;
|
|
4669
|
+
}
|
|
4670
|
+
stats.attempts += 1;
|
|
4671
|
+
stats.lastSeen = now;
|
|
4672
|
+
}
|
|
4673
|
+
report() {
|
|
4674
|
+
return [...this.entries].map(([path, stats]) => ({
|
|
4675
|
+
path,
|
|
4676
|
+
...stats
|
|
4677
|
+
})).sort((a, b) => b.lastSeen - a.lastSeen);
|
|
4678
|
+
}
|
|
4679
|
+
};
|
|
4635
4680
|
/** File-backed store shared by every gateway instance (LAN and remote). */
|
|
4636
4681
|
var WebSocketPathStore = class {
|
|
4637
4682
|
file;
|
|
@@ -7868,7 +7913,9 @@ var CpolarComponentManager = class {
|
|
|
7868
7913
|
const PACKAGE_NAME = "dsh-mobile";
|
|
7869
7914
|
const NPM_LATEST_URL = "https://registry.npmjs.org/dsh-mobile/latest";
|
|
7870
7915
|
const GITHUB_LATEST_URL = "https://github.com/saya-ch/dsh-mobile/releases/latest";
|
|
7916
|
+
const GITHUB_API_LATEST_URL = "https://api.github.com/repos/saya-ch/dsh-mobile/releases/latest";
|
|
7871
7917
|
const GITHUB_RELEASES_URL = "https://github.com/saya-ch/dsh-mobile/releases";
|
|
7918
|
+
const RELEASE_NOTES_MAX_CHARS = 4e3;
|
|
7872
7919
|
const STATUS_CACHE_MS = 6e5;
|
|
7873
7920
|
const REQUEST_TIMEOUT_MS = 8e3;
|
|
7874
7921
|
const UPDATE_TIMEOUT_MS = 12e4;
|
|
@@ -8008,6 +8055,21 @@ async function fetchAndroidVersion(fetcher) {
|
|
|
8008
8055
|
});
|
|
8009
8056
|
return githubReleaseVersion(response.headers.get("location"), response.url);
|
|
8010
8057
|
}
|
|
8058
|
+
/** Best-effort body of the latest GitHub release, trimmed to a bounded size. */
|
|
8059
|
+
async function fetchReleaseNotes(fetcher) {
|
|
8060
|
+
const response = await fetcher(GITHUB_API_LATEST_URL, {
|
|
8061
|
+
headers: {
|
|
8062
|
+
accept: "application/vnd.github+json",
|
|
8063
|
+
"user-agent": "dsh-mobile-release-check"
|
|
8064
|
+
},
|
|
8065
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
8066
|
+
});
|
|
8067
|
+
if (!response.ok) return void 0;
|
|
8068
|
+
const payload = await response.json();
|
|
8069
|
+
if (typeof payload.body !== "string") return void 0;
|
|
8070
|
+
const notes = payload.body.trim();
|
|
8071
|
+
return notes === "" ? void 0 : notes.slice(0, RELEASE_NOTES_MAX_CHARS);
|
|
8072
|
+
}
|
|
8011
8073
|
async function readProfileInstalledVersion(profileDirectory) {
|
|
8012
8074
|
try {
|
|
8013
8075
|
const manifestPath = createRequire(join(profileDirectory, "package.json")).resolve(`${PACKAGE_NAME}/package.json`);
|
|
@@ -8200,9 +8262,14 @@ var PluginReleaseManager = class {
|
|
|
8200
8262
|
async status(force = false) {
|
|
8201
8263
|
if (!force && this.cache !== void 0 && this.cache.expiresAt > this.now()) return this.cache.status;
|
|
8202
8264
|
const updateSupported = isRegistryPluginSpec(this.profileDirectory === void 0 ? void 0 : await profileDependencySpec(this.profileDirectory));
|
|
8203
|
-
const [npmResult, androidResult] = await Promise.allSettled([
|
|
8265
|
+
const [npmResult, androidResult, notesResult] = await Promise.allSettled([
|
|
8266
|
+
fetchNpmVersion(this.fetcher),
|
|
8267
|
+
fetchAndroidVersion(this.fetcher),
|
|
8268
|
+
fetchReleaseNotes(this.fetcher)
|
|
8269
|
+
]);
|
|
8204
8270
|
const latestVersion = npmResult.status === "fulfilled" ? npmResult.value : void 0;
|
|
8205
8271
|
const androidVersion = androidResult.status === "fulfilled" ? androidResult.value : void 0;
|
|
8272
|
+
const releaseNotes = notesResult.status === "fulfilled" ? notesResult.value : void 0;
|
|
8206
8273
|
const comparison = latestVersion === void 0 ? void 0 : comparePluginVersions(latestVersion, this.installedVersion);
|
|
8207
8274
|
const status = Object.freeze({
|
|
8208
8275
|
installedVersion: this.installedVersion,
|
|
@@ -8210,7 +8277,8 @@ var PluginReleaseManager = class {
|
|
|
8210
8277
|
updateAvailable: updateSupported && comparison === 1,
|
|
8211
8278
|
updateSupported,
|
|
8212
8279
|
...androidVersion === void 0 ? {} : { androidVersion },
|
|
8213
|
-
androidDownloadUrl: androidReleaseDownloadUrl(androidVersion)
|
|
8280
|
+
androidDownloadUrl: androidReleaseDownloadUrl(androidVersion),
|
|
8281
|
+
...releaseNotes === void 0 ? {} : { releaseNotes }
|
|
8214
8282
|
});
|
|
8215
8283
|
this.cache = {
|
|
8216
8284
|
expiresAt: this.now() + STATUS_CACHE_MS,
|
|
@@ -8735,10 +8803,11 @@ async function apply(ctx, config) {
|
|
|
8735
8803
|
});
|
|
8736
8804
|
const webSocketPaths = new WebSocketPathStore(join(stateDirectory, "websocket-paths.json"));
|
|
8737
8805
|
await webSocketPaths.load();
|
|
8806
|
+
const blockedUpgradePaths = new BlockedUpgradePathLog();
|
|
8738
8807
|
let lanGateway;
|
|
8739
8808
|
const startGateway = async (candidateConfig) => {
|
|
8740
8809
|
const resolved = parseGatewayConfig(candidateConfig);
|
|
8741
|
-
const candidate = new MobileAccessGateway(resolved, new JsonDeviceStore(resolved.stateFile, resolved.maxDevices), mobileAccess, upstreamLoginUrl, webSocketPaths);
|
|
8810
|
+
const candidate = new MobileAccessGateway(resolved, new JsonDeviceStore(resolved.stateFile, resolved.maxDevices), mobileAccess, upstreamLoginUrl, webSocketPaths, blockedUpgradePaths);
|
|
8742
8811
|
await candidate.start();
|
|
8743
8812
|
lanGateway = candidate;
|
|
8744
8813
|
return { close: async () => {
|
|
@@ -8778,7 +8847,7 @@ async function apply(ctx, config) {
|
|
|
8778
8847
|
}
|
|
8779
8848
|
const createRemoteGateway = async (publicOrigin, listenPort = 0) => {
|
|
8780
8849
|
const resolved = remoteGatewayConfig(template, publicOrigin, remoteDeviceFile, instanceId, listenPort);
|
|
8781
|
-
const candidate = new MobileAccessGateway(resolved, new JsonDeviceStore(resolved.stateFile, resolved.maxDevices), mobileAccess, upstreamLoginUrl, webSocketPaths);
|
|
8850
|
+
const candidate = new MobileAccessGateway(resolved, new JsonDeviceStore(resolved.stateFile, resolved.maxDevices), mobileAccess, upstreamLoginUrl, webSocketPaths, blockedUpgradePaths);
|
|
8782
8851
|
await candidate.start();
|
|
8783
8852
|
return candidate;
|
|
8784
8853
|
};
|
|
@@ -8944,6 +9013,10 @@ async function apply(ctx, config) {
|
|
|
8944
9013
|
sendJson(response, 200, { paths: webSocketPaths.list() }, false);
|
|
8945
9014
|
return;
|
|
8946
9015
|
}
|
|
9016
|
+
if (request.method === "GET" && target.decodedPathname === `/api/mobile-access/remote/websocket-paths/blocked`) {
|
|
9017
|
+
sendJson(response, 200, { blocked: blockedUpgradePaths.report() }, false);
|
|
9018
|
+
return;
|
|
9019
|
+
}
|
|
8947
9020
|
if (request.method === "POST" && target.decodedPathname === `/api/mobile-access/remote/websocket-paths`) {
|
|
8948
9021
|
const body = await readJsonObject(request, 4096);
|
|
8949
9022
|
if (!Array.isArray(body.paths)) throw new HttpError(400, "bad_request");
|
|
@@ -9177,6 +9250,6 @@ async function apply(ctx, config) {
|
|
|
9177
9250
|
}, "dsh-mobile: independent LAN and selectable remote providers with /mobile command");
|
|
9178
9251
|
}
|
|
9179
9252
|
//#endregion
|
|
9180
|
-
export { AUTH_PREFIX, AccessController, AccessError, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, FrpConfigStore, FrpController, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, MobileAccessGateway, MobileAccessGatewayController, MobileAccessService, MobileExtensionError, RequestTrustPolicy, SESSION_COOKIE, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath };
|
|
9253
|
+
export { AUTH_PREFIX, AccessController, AccessError, BlockedUpgradePathLog, BoundedRateLimiter, CSRF_COOKIE, CSRF_HEADER, Config, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, EXTENSION_LIMITS, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FrpComponentManager, FrpConfigStore, FrpController, JsonDeviceStore, JsonMobileAccessControlStore, JsonRemoteProviderStore, LOCAL_ADMIN_PREFIX, MAX_BLOCKED_UPGRADE_PATHS, MAX_EXTRA_WEBSOCKET_PATHS, MAX_WEBSOCKET_PATH_LENGTH, MemoryDeviceStore, MobileAccessGateway, MobileAccessGatewayController, MobileAccessService, MobileExtensionError, RequestTrustPolicy, SESSION_COOKIE, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, parseAuthority, parseCidr, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateWebSocketPath };
|
|
9181
9254
|
|
|
9182
9255
|
//# sourceMappingURL=index.mjs.map
|