dsh-mobile 0.4.5 → 0.4.6
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/CONTRIBUTORS.md +5 -3
- package/README.en.md +23 -11
- package/README.md +23 -11
- package/SECURITY.md +7 -5
- package/docs/ATTACH_EXISTING_FRPS.en.md +44 -0
- package/docs/ATTACH_EXISTING_FRPS.md +98 -0
- package/docs/README.md +3 -0
- package/docs/SELF_HOSTED_FRP.en.md +3 -1
- package/docs/SELF_HOSTED_FRP.md +7 -1
- package/lib/cli.js +52 -15
- package/lib/cli.js.map +1 -1
- package/lib/client.js +1235 -155
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +384 -10
- package/lib/index.mjs +2204 -637
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-compat.js.map +1 -1
- package/package.json +18 -14
package/lib/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { X509Certificate } from "node:crypto";
|
|
1
2
|
import z from "@deepseek-ai/schemastery";
|
|
2
3
|
import { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
3
4
|
import { Readable } from "node:stream";
|
|
@@ -649,6 +650,8 @@ declare class MobileAccessGateway {
|
|
|
649
650
|
} | undefined, blockedUpgradeLog?: BlockedUpgradePathLog | undefined, onDiscoveryDegraded?: ((source: 'broadcast' | 'mdns', code: string) => void) | undefined);
|
|
650
651
|
/** Initialize durable state, validate TLS, and bind the externally reachable listener. */
|
|
651
652
|
start(): Promise<void>;
|
|
653
|
+
/** Install a newly signed provided leaf for future TLS handshakes without dropping sessions. */
|
|
654
|
+
refreshProvidedTls(): Promise<void>;
|
|
652
655
|
private startDiscovery;
|
|
653
656
|
private reportDiscoveryDegraded;
|
|
654
657
|
private recordBroadcastFailure;
|
|
@@ -839,12 +842,51 @@ declare const FRP_CADDY_SNIPPET_PATH = "/etc/caddy/dsh-mobile-dsh.caddy";
|
|
|
839
842
|
declare const FRP_CADDY_SNIPPET_MARKER = "# Managed by DSH Mobile - snippet, safe to delete";
|
|
840
843
|
/** Exact line the main Caddyfile must contain (uncommented) for the site to load. */
|
|
841
844
|
declare const FRP_CADDY_IMPORT_LINE = "import /etc/caddy/dsh-mobile-dsh.caddy";
|
|
842
|
-
/**
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Entry TLS mode for the FRP channel.
|
|
847
|
+
*
|
|
848
|
+
* - `public-ip-cert` (default): the VPS Caddy terminates TLS with a public-CA
|
|
849
|
+
* certificate and reverse-proxies the plaintext vhost to frps.
|
|
850
|
+
* - `self-signed`: no Caddy and no public certificate at all. frps publishes a
|
|
851
|
+
* raw TCP proxy and the DSH gateway terminates TLS itself with a leaf signed
|
|
852
|
+
* by its own pairing CA, which the Android app pins through `ca.cer`.
|
|
853
|
+
*/
|
|
854
|
+
type FrpEntryTls = 'public-ip-cert' | 'self-signed';
|
|
855
|
+
/** Optional overrides for the generated Caddy site; every field defaults to the upstream value. */
|
|
856
|
+
interface CaddySiteOptions {
|
|
857
|
+
readonly certDir?: string;
|
|
858
|
+
/**
|
|
859
|
+
* The user's real `vhostHTTPPort`. `attach` mode must never assume the
|
|
860
|
+
* upstream 7080: a wrong port silently disables the plaintext-exposure gate.
|
|
861
|
+
*/
|
|
862
|
+
readonly vhostHttpPort?: number;
|
|
863
|
+
/** `self-signed` is a TCP passthrough and never produces a Caddy site. */
|
|
864
|
+
readonly entryTls?: FrpEntryTls;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Build the Caddy site for one public host (without markers or import wiring).
|
|
868
|
+
*
|
|
869
|
+
* The second parameter accepts either a bare certificate directory (the legacy
|
|
870
|
+
* signature) or a full {@link CaddySiteOptions} object, so existing callers keep
|
|
871
|
+
* working unchanged.
|
|
872
|
+
*/
|
|
873
|
+
declare function createCaddySite(publicHost: string, options?: CaddySiteOptions | string): string;
|
|
874
|
+
/**
|
|
875
|
+
* Build the only supported frps config and Caddy snippet from validated user inputs.
|
|
876
|
+
*
|
|
877
|
+
* Default `options` reproduce the upstream artefact byte for byte; `attach` mode
|
|
878
|
+
* passes the user's real vhost port, and `self-signed` is rejected because that
|
|
879
|
+
* mode publishes a raw TCP proxy instead of an HTTP vhost.
|
|
880
|
+
*/
|
|
881
|
+
declare function createRestrictedFrpServerTemplate(serverPort: number, token: string, publicOrigin: string, options?: CaddySiteOptions): string;
|
|
846
882
|
//#endregion
|
|
847
883
|
//#region src/frp-config.d.ts
|
|
884
|
+
/** How the restricted FRP channel is provisioned on the VPS. */
|
|
885
|
+
type FrpMode = 'deploy' | 'attach';
|
|
886
|
+
/** Public entry port used by the self-signed TCP passthrough (never 443 by requirement). */
|
|
887
|
+
declare const FRP_DEFAULT_PUBLIC_PORT = 33080;
|
|
888
|
+
/** Ports owned by other DSH Mobile listeners; the public entry may never reuse them. */
|
|
889
|
+
declare const FRP_RESERVED_PORTS: readonly number[];
|
|
848
890
|
/** Credentials and endpoints required by the restricted FRP provider. */
|
|
849
891
|
interface FrpSettings {
|
|
850
892
|
readonly version: 1;
|
|
@@ -852,6 +894,17 @@ interface FrpSettings {
|
|
|
852
894
|
readonly serverPort: number;
|
|
853
895
|
readonly token: string;
|
|
854
896
|
readonly publicOrigin: string;
|
|
897
|
+
/**
|
|
898
|
+
* `deploy` (default) installs the plugin's own frps on the VPS.
|
|
899
|
+
* `attach` reuses an frps that already runs there and never touches it.
|
|
900
|
+
*/
|
|
901
|
+
readonly mode?: FrpMode;
|
|
902
|
+
/** `public-ip-cert` (default) or the gateway-terminated `self-signed` passthrough. */
|
|
903
|
+
readonly entryTls?: FrpEntryTls;
|
|
904
|
+
/** The real `vhostHTTPPort` of the user's frps; defaults to the upstream 7080. */
|
|
905
|
+
readonly vhostHttpPort?: number;
|
|
906
|
+
/** Public entry port of the self-signed TCP proxy; defaults to 33080. */
|
|
907
|
+
readonly publicPort?: number;
|
|
855
908
|
}
|
|
856
909
|
/** Safe FRP configuration fields returned to the desktop UI. */
|
|
857
910
|
interface FrpConfigurationStatus {
|
|
@@ -862,6 +915,12 @@ interface FrpConfigurationStatus {
|
|
|
862
915
|
readonly vhostHttpPort: number;
|
|
863
916
|
readonly storagePath: string;
|
|
864
917
|
readonly errorCode?: string;
|
|
918
|
+
/** Present only when the saved configuration leaves the upstream `deploy` default. */
|
|
919
|
+
readonly mode?: FrpMode;
|
|
920
|
+
/** Present only when the saved configuration uses the self-signed entry. */
|
|
921
|
+
readonly entryTls?: FrpEntryTls;
|
|
922
|
+
/** Present only when a non-default public entry port is saved. */
|
|
923
|
+
readonly publicPort?: number;
|
|
865
924
|
}
|
|
866
925
|
/** Validate the FRP server hostname or IP address. */
|
|
867
926
|
declare function validateFrpServerAddress(value: unknown): string;
|
|
@@ -871,7 +930,34 @@ declare function validateFrpServerPort(value: unknown): number;
|
|
|
871
930
|
declare function validateFrpToken(value: unknown): string;
|
|
872
931
|
/** Validate the public HTTPS origin used by Caddy and Android pairing. */
|
|
873
932
|
declare function validateFrpPublicOrigin(value: unknown): string;
|
|
874
|
-
/**
|
|
933
|
+
/** Validate the provisioning mode. */
|
|
934
|
+
declare function validateFrpMode(value: unknown): FrpMode;
|
|
935
|
+
/** Validate the entry TLS mode. */
|
|
936
|
+
declare function validateFrpEntryTls(value: unknown): FrpEntryTls;
|
|
937
|
+
/** Validate the loopback vhost port of the target frps. */
|
|
938
|
+
declare function validateFrpVhostHttpPort(value: unknown): number;
|
|
939
|
+
/** Validate the public entry port of the self-signed TCP proxy. */
|
|
940
|
+
declare function validateFrpPublicPort(value: unknown): number;
|
|
941
|
+
/** Effective provisioning mode; an absent field keeps the upstream behaviour. */
|
|
942
|
+
declare function resolveFrpMode(settings: FrpSettings): FrpMode;
|
|
943
|
+
/** Effective entry TLS mode; an absent field keeps the upstream behaviour. */
|
|
944
|
+
declare function resolveFrpEntryTls(settings: FrpSettings): FrpEntryTls;
|
|
945
|
+
/** Effective loopback vhost port; an absent field keeps the upstream behaviour. */
|
|
946
|
+
declare function resolveFrpVhostHttpPort(settings: FrpSettings): number;
|
|
947
|
+
/** Effective public entry port of the self-signed passthrough. */
|
|
948
|
+
declare function resolveFrpPublicPort(settings: FrpSettings): number;
|
|
949
|
+
/** True when the gateway terminates TLS itself behind a raw frps TCP proxy. */
|
|
950
|
+
declare function isFrpSelfSignedIngress(settings: FrpSettings): boolean;
|
|
951
|
+
/**
|
|
952
|
+
* Parse FRP settings at the loopback request and filesystem boundaries.
|
|
953
|
+
*
|
|
954
|
+
* Optional keys are kept only when supplied, so a legacy `settings.json` still
|
|
955
|
+
* round-trips byte for byte and every default stays the upstream behaviour.
|
|
956
|
+
* Two cross-field rules are enforced here because neither can be recovered later:
|
|
957
|
+
* the self-signed entry is a TCP passthrough and therefore attach-only, and
|
|
958
|
+
* attach mode with a public-CA entry must state the user's real vhost port —
|
|
959
|
+
* silently assuming 7080 would disable the plaintext-exposure gate.
|
|
960
|
+
*/
|
|
875
961
|
declare function parseFrpSettings(value: unknown): FrpSettings;
|
|
876
962
|
/**
|
|
877
963
|
* Merge a partial VPS request body with the saved configuration so a blank
|
|
@@ -885,7 +971,13 @@ declare function mergeSavedFrpTarget(partial: Readonly<Record<string, unknown>>,
|
|
|
885
971
|
readonly serverAddress: string;
|
|
886
972
|
readonly serverPort: number;
|
|
887
973
|
};
|
|
888
|
-
/**
|
|
974
|
+
/**
|
|
975
|
+
* Build the single-purpose frpc configuration for the current loopback gateway.
|
|
976
|
+
*
|
|
977
|
+
* The default (public-CA) entry is an HTTP vhost behind Caddy and is emitted byte
|
|
978
|
+
* for byte as before. The self-signed entry cannot use a vhost at all: frps only
|
|
979
|
+
* forwards raw TCP, and the gateway terminates TLS on that connection.
|
|
980
|
+
*/
|
|
889
981
|
declare function createFrpcToml(settings: FrpSettings, localPort: number): string;
|
|
890
982
|
/** Build the matching restricted frps and Caddy templates for one VPS. */
|
|
891
983
|
declare function createFrpServerTemplate(settings: FrpSettings): string;
|
|
@@ -899,7 +991,13 @@ declare class FrpConfigStore {
|
|
|
899
991
|
constructor(stateDirectory: string);
|
|
900
992
|
/** Load private settings while rejecting links, oversized files, and unknown fields. */
|
|
901
993
|
initialize(): Promise<void>;
|
|
902
|
-
/**
|
|
994
|
+
/**
|
|
995
|
+
* Return configuration metadata without exposing the FRP token.
|
|
996
|
+
*
|
|
997
|
+
* The optional keys appear only when the saved configuration departs from the
|
|
998
|
+
* upstream defaults, so the pre-existing field set is unchanged for every
|
|
999
|
+
* legacy configuration.
|
|
1000
|
+
*/
|
|
903
1001
|
status(): FrpConfigurationStatus;
|
|
904
1002
|
/** Return private settings only to the provider lifecycle. */
|
|
905
1003
|
settings(): FrpSettings | undefined;
|
|
@@ -911,6 +1009,226 @@ declare class FrpConfigStore {
|
|
|
911
1009
|
purge(): Promise<FrpConfigurationStatus>;
|
|
912
1010
|
}
|
|
913
1011
|
//#endregion
|
|
1012
|
+
//#region src/frp-attach.d.ts
|
|
1013
|
+
/** Default proof path used to confirm the public entry answered from this computer. */
|
|
1014
|
+
declare const FRP_ATTACH_DISCOVERY_PATH = "/mobile-access/discovery";
|
|
1015
|
+
/** Declaration printed above the VPS half of an attach template. */
|
|
1016
|
+
declare const FRP_ATTACH_VPS_DECLARATION: string;
|
|
1017
|
+
/** Declaration printed above the local half of an attach template. */
|
|
1018
|
+
declare const FRP_ATTACH_LOCAL_DECLARATION = "# 本机只写入 frpc.toml 并启动 frpc:不安装、不改动本机 frps,也不改动 DSH 自身配置。";
|
|
1019
|
+
/** Declaration for the self-signed passthrough, which keeps its CA on this computer. */
|
|
1020
|
+
declare const FRP_ATTACH_SELF_SIGNED_DECLARATION: string;
|
|
1021
|
+
/** Optional inputs for attach artefacts; every field falls back to the validated settings. */
|
|
1022
|
+
interface FrpAttachOptions {
|
|
1023
|
+
readonly vhostHttpPort?: number;
|
|
1024
|
+
readonly publicPort?: number;
|
|
1025
|
+
readonly certDir?: string;
|
|
1026
|
+
/** Absolute path of the plugin-written frpc.toml, used for the `frpc verify` self-check. */
|
|
1027
|
+
readonly configFile?: string;
|
|
1028
|
+
/** Loopback port the gateway will listen on; only a placeholder inside the copied runbook. */
|
|
1029
|
+
readonly localPort?: number;
|
|
1030
|
+
/**
|
|
1031
|
+
* Explicit reveal of the shared token inside previews and clipboard copies.
|
|
1032
|
+
*
|
|
1033
|
+
* Defaults to `false`: every artefact the panel produces on its own stays
|
|
1034
|
+
* masked, because the copied text lands in the system clipboard. Only the
|
|
1035
|
+
* panel's dedicated "copy the frpc.toml with its token" action sets this, and
|
|
1036
|
+
* the result never reaches a stored state, a log, or localStorage.
|
|
1037
|
+
*/
|
|
1038
|
+
readonly revealToken?: boolean;
|
|
1039
|
+
}
|
|
1040
|
+
/** The two separated halves of the attach artefact, plus their combined text. */
|
|
1041
|
+
interface FrpAttachTemplate {
|
|
1042
|
+
readonly mode: 'attach';
|
|
1043
|
+
readonly vps: string;
|
|
1044
|
+
readonly local: string;
|
|
1045
|
+
readonly text: string;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Reject every attach request that could not be carried out safely before any
|
|
1049
|
+
* artefact is produced. Attach never installs frps, so it must know the user's
|
|
1050
|
+
* real vhost port (unless the self-signed passthrough removes the vhost entirely).
|
|
1051
|
+
*/
|
|
1052
|
+
declare function validateAttachSettings(settings: FrpSettings, options?: FrpAttachOptions): void;
|
|
1053
|
+
/** Shared VPS-side inputs of both the copied runbook and the panel plan. */
|
|
1054
|
+
interface FrpAttachVpsParts {
|
|
1055
|
+
readonly publicHost: string;
|
|
1056
|
+
readonly selfSigned: boolean;
|
|
1057
|
+
readonly vhostHttpPort?: number;
|
|
1058
|
+
readonly publicPort?: number;
|
|
1059
|
+
readonly snippet: string;
|
|
1060
|
+
readonly certGuide: readonly string[];
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Derive every VPS-side value once so the copied runbook and the panel plan can
|
|
1064
|
+
* never drift apart.
|
|
1065
|
+
*/
|
|
1066
|
+
declare function frpAttachVpsParts(settings: FrpSettings, options?: FrpAttachOptions): FrpAttachVpsParts;
|
|
1067
|
+
/**
|
|
1068
|
+
* Build the attach artefact for an existing frps.
|
|
1069
|
+
*
|
|
1070
|
+
* The result is deliberately split in two: the VPS half contains only what the
|
|
1071
|
+
* user's own server needs (Caddy snippet + import + certificate guidance, or a
|
|
1072
|
+
* single firewall rule for the self-signed passthrough), and the local half
|
|
1073
|
+
* contains the generated frpc.toml plus its `frpc verify` self-check. Neither
|
|
1074
|
+
* half installs, rewrites, or restarts the user's frps.
|
|
1075
|
+
*/
|
|
1076
|
+
declare function createFrpAttachTemplateParts(settings: FrpSettings, options?: FrpAttachOptions): FrpAttachTemplate;
|
|
1077
|
+
/** Combined attach artefact, ready for the clipboard. */
|
|
1078
|
+
declare function createFrpAttachTemplate(settings: FrpSettings, options?: FrpAttachOptions): string;
|
|
1079
|
+
//#endregion
|
|
1080
|
+
//#region src/frp-attach-plan.d.ts
|
|
1081
|
+
/** Stable step identifiers; the panel maps each one to a translated title. */
|
|
1082
|
+
type FrpAttachStepId = 'write-snippet' | 'add-import' | 'issue-ip-cert' | 'enable-cert-timer' | 'verify-https' | 'open-public-port' | 'verify-frps' | 'verify-entry';
|
|
1083
|
+
/** One actionable VPS-side step; `title` is a message key, `label` the copied text. */
|
|
1084
|
+
interface FrpAttachPlanStep {
|
|
1085
|
+
readonly id: FrpAttachStepId;
|
|
1086
|
+
readonly title: string;
|
|
1087
|
+
readonly label: string;
|
|
1088
|
+
readonly commands: readonly string[];
|
|
1089
|
+
readonly optional: boolean;
|
|
1090
|
+
readonly verifyHint: string;
|
|
1091
|
+
}
|
|
1092
|
+
/** The local half of the plan: the exact frpc.toml plus its self-check command. */
|
|
1093
|
+
interface FrpAttachPlanLocal {
|
|
1094
|
+
/** The frpc.toml as previewed: masked unless the caller explicitly revealed the token. */
|
|
1095
|
+
readonly frpcToml: string;
|
|
1096
|
+
/** True when `frpcToml` carries the fixed placeholder instead of the shared token. */
|
|
1097
|
+
readonly tokenMasked: boolean;
|
|
1098
|
+
readonly verifyCommand: string;
|
|
1099
|
+
readonly configFile: string;
|
|
1100
|
+
readonly declaration: string;
|
|
1101
|
+
}
|
|
1102
|
+
/** Zero-SSH plan for attaching to an frps the user already runs. */
|
|
1103
|
+
interface FrpAttachPlan {
|
|
1104
|
+
readonly mode: 'attach';
|
|
1105
|
+
readonly entryTls: FrpEntryTls;
|
|
1106
|
+
readonly vhostHttpPort?: number;
|
|
1107
|
+
readonly publicPort?: number;
|
|
1108
|
+
readonly local: FrpAttachPlanLocal;
|
|
1109
|
+
readonly vps: readonly FrpAttachPlanStep[];
|
|
1110
|
+
readonly warnings: readonly string[];
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Build the copy-only attach plan. It performs no network access, no SSH, and no
|
|
1114
|
+
* filesystem write: the caller renders or copies the steps and the local frpc
|
|
1115
|
+
* configuration is written by the ordinary provider lifecycle.
|
|
1116
|
+
*/
|
|
1117
|
+
declare function createFrpAttachPlan(settings: FrpSettings, options?: FrpAttachOptions): FrpAttachPlan;
|
|
1118
|
+
//#endregion
|
|
1119
|
+
//#region src/cert-renewal.d.ts
|
|
1120
|
+
/** Days left below which the entry certificate is reported as expiring. */
|
|
1121
|
+
declare const CERT_EXPIRING_DAYS = 2;
|
|
1122
|
+
/** Read-only lifetime verdict for one certificate; never mutates or renews anything. */
|
|
1123
|
+
interface CertRenewalStatus {
|
|
1124
|
+
readonly state: 'ok' | 'expiring' | 'expired' | 'unknown';
|
|
1125
|
+
/** Unix milliseconds of `notAfter`. */
|
|
1126
|
+
readonly notAfter?: number;
|
|
1127
|
+
readonly daysRemaining?: number;
|
|
1128
|
+
readonly subject?: string;
|
|
1129
|
+
readonly issuer?: string;
|
|
1130
|
+
readonly errorCode?: string;
|
|
1131
|
+
}
|
|
1132
|
+
/** Evaluate one `notAfter` timestamp against the current clock. */
|
|
1133
|
+
declare function evaluateCertificateLifetime(notAfter: number, now?: number): CertRenewalStatus;
|
|
1134
|
+
/**
|
|
1135
|
+
* Read one PEM certificate from disk and report only its lifetime.
|
|
1136
|
+
*
|
|
1137
|
+
* A missing or unreadable file yields `unknown` with the stable
|
|
1138
|
+
* `frp_attach_cert_unknown` code so the panel can explain how to re-issue it.
|
|
1139
|
+
*/
|
|
1140
|
+
declare function readCertificateRenewal(file: string, now?: number): Promise<CertRenewalStatus>;
|
|
1141
|
+
/**
|
|
1142
|
+
* Ask a live TLS endpoint for its leaf certificate and report its lifetime.
|
|
1143
|
+
*
|
|
1144
|
+
* Verification is intentionally skipped: this is a read-only lifetime probe for
|
|
1145
|
+
* an endpoint whose trust anchor is already pinned elsewhere, and a self-signed
|
|
1146
|
+
* leaf is the expected answer for the passthrough entry.
|
|
1147
|
+
*/
|
|
1148
|
+
declare function probeOriginCertificate(host: string, port: number, timeoutMs?: number): Promise<CertRenewalStatus>;
|
|
1149
|
+
//#endregion
|
|
1150
|
+
//#region src/frp-ingress.d.ts
|
|
1151
|
+
/** Private files owned by the self-signed FRP ingress. */
|
|
1152
|
+
interface FrpIngressPaths {
|
|
1153
|
+
readonly directory: string;
|
|
1154
|
+
readonly caCertFile: string;
|
|
1155
|
+
readonly caKeyFile: string;
|
|
1156
|
+
readonly certFile: string;
|
|
1157
|
+
readonly keyFile: string;
|
|
1158
|
+
readonly statusFile: string;
|
|
1159
|
+
}
|
|
1160
|
+
/** Signed ingress material plus the fingerprint the app must pin. */
|
|
1161
|
+
interface FrpIngressCertificate {
|
|
1162
|
+
readonly paths: FrpIngressPaths;
|
|
1163
|
+
readonly ca: X509Certificate;
|
|
1164
|
+
readonly leaf: X509Certificate;
|
|
1165
|
+
readonly caFingerprint: string;
|
|
1166
|
+
readonly status: CertRenewalStatus;
|
|
1167
|
+
}
|
|
1168
|
+
/** Everything the panel needs for the on-demand self-check. */
|
|
1169
|
+
interface FrpIngressSelfCheck {
|
|
1170
|
+
readonly mode: 'deploy' | 'attach';
|
|
1171
|
+
readonly entryTls: 'public-ip-cert' | 'self-signed';
|
|
1172
|
+
readonly vhostHttpPort: number;
|
|
1173
|
+
readonly publicPort: number;
|
|
1174
|
+
readonly publicOrigin: string;
|
|
1175
|
+
/** Reachable HTTPS entry; includes the TCP proxy port in self-signed mode. */
|
|
1176
|
+
readonly entryOrigin: string;
|
|
1177
|
+
readonly serverAddress: string;
|
|
1178
|
+
readonly serverPort: number;
|
|
1179
|
+
readonly caFingerprint?: string;
|
|
1180
|
+
readonly certificate?: CertRenewalStatus;
|
|
1181
|
+
readonly caCertificate?: CertRenewalStatus;
|
|
1182
|
+
readonly inbound: {
|
|
1183
|
+
readonly listenHost: '127.0.0.1';
|
|
1184
|
+
readonly allowedCidrs: readonly string[];
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
/** Private ingress directory, always a sibling of the remote device file. */
|
|
1188
|
+
declare function frpIngressPaths(stateFile: string): FrpIngressPaths;
|
|
1189
|
+
/**
|
|
1190
|
+
* Materialize the CA and leaf the gateway terminates TLS with.
|
|
1191
|
+
*
|
|
1192
|
+
* The CA remains stable for paired phones; an expired CA must be re-paired, not
|
|
1193
|
+
* replaced silently. The leaf is re-signed when expiring or no longer valid for
|
|
1194
|
+
* the public IPv4, and the running gateway reloads it after a renewal check.
|
|
1195
|
+
*/
|
|
1196
|
+
declare function ensureFrpIngressCertificate(settings: FrpSettings, stateFile: string, now?: number, expectedCaFingerprint?: string): Promise<FrpIngressCertificate>;
|
|
1197
|
+
/**
|
|
1198
|
+
* Build the read-only self-check payload shown in the desktop panel.
|
|
1199
|
+
*
|
|
1200
|
+
* No secret ever leaves this function: the CA is reported by fingerprint only,
|
|
1201
|
+
* and the token is never read.
|
|
1202
|
+
*/
|
|
1203
|
+
declare function frpIngressSelfCheck(settings: FrpSettings, stateFile: string): Promise<FrpIngressSelfCheck>;
|
|
1204
|
+
//#endregion
|
|
1205
|
+
//#region src/managed-setup.d.ts
|
|
1206
|
+
/** One host a server leaf must be valid for: an IP literal, a DNS name, or both. */
|
|
1207
|
+
interface ServerCertificateTarget {
|
|
1208
|
+
readonly commonName: string;
|
|
1209
|
+
readonly ipAddresses?: readonly string[];
|
|
1210
|
+
readonly dnsNames?: readonly string[];
|
|
1211
|
+
}
|
|
1212
|
+
/** Where a freshly signed server leaf is installed. */
|
|
1213
|
+
interface ServerCertificateFiles {
|
|
1214
|
+
readonly certFile: string;
|
|
1215
|
+
readonly keyFile: string;
|
|
1216
|
+
}
|
|
1217
|
+
/** CA material a leaf is signed with. */
|
|
1218
|
+
interface ServerCertificateAuthority {
|
|
1219
|
+
readonly caCertFile: string;
|
|
1220
|
+
readonly caKeyFile: string;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Sign one server leaf with an existing self-signed CA and install it privately.
|
|
1224
|
+
*
|
|
1225
|
+
* Both the LAN listener and the self-signed FRP ingress use this one path, so a
|
|
1226
|
+
* certificate can never be produced by two divergent code paths. IP entries are
|
|
1227
|
+
* required for console addresses (`type: 7`), DNS entries (`type: 2`) cover named
|
|
1228
|
+
* hosts; the Android client accepts either through its pinned CA.
|
|
1229
|
+
*/
|
|
1230
|
+
declare function issueServerCertificate(authority: ServerCertificateAuthority, target: ServerCertificateTarget, output: ServerCertificateFiles, lifetimeDays?: number): Promise<void>;
|
|
1231
|
+
//#endregion
|
|
914
1232
|
//#region src/remote.d.ts
|
|
915
1233
|
/** Remote transports supported by the desktop plugin and Android client. */
|
|
916
1234
|
type RemoteProvider = 'tailscale' | 'cpolar' | 'cloudflared' | 'frp' | 'origin';
|
|
@@ -963,18 +1281,59 @@ interface FrpStatus {
|
|
|
963
1281
|
readonly origin?: string;
|
|
964
1282
|
readonly errorCode?: string;
|
|
965
1283
|
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Explicit target of the start-up discovery self-check.
|
|
1286
|
+
*
|
|
1287
|
+
* The target is derived from the effective entry, never assumed: the public-CA
|
|
1288
|
+
* entry answers on the saved origin (443 behind Caddy, publicly trusted chain),
|
|
1289
|
+
* while the self-signed entry is a raw TCP passthrough on `publicPort` whose
|
|
1290
|
+
* leaf chains to the plugin's own ingress CA.
|
|
1291
|
+
*/
|
|
1292
|
+
interface FrpDiscoveryProbeTarget {
|
|
1293
|
+
/** Absolute HTTPS origin to dial, including the public entry port. */
|
|
1294
|
+
readonly origin: string;
|
|
1295
|
+
/**
|
|
1296
|
+
* PEM bundle that anchors the entry leaf in place of the system trust store.
|
|
1297
|
+
* Absent keeps the default chain, which is correct for a publicly trusted
|
|
1298
|
+
* certificate; it is never a way to skip verification.
|
|
1299
|
+
*/
|
|
1300
|
+
readonly trustAnchorPem?: string;
|
|
1301
|
+
}
|
|
966
1302
|
/** Inputs for one FRP client process and authenticated DSH gateway. */
|
|
967
1303
|
interface FrpControllerOptions {
|
|
968
1304
|
readonly store: MobileAccessControlStore;
|
|
969
1305
|
readonly executable: string;
|
|
970
1306
|
readonly config: FrpConfigStore;
|
|
1307
|
+
/**
|
|
1308
|
+
* Plugin-wide installation identity (the LAN pairing CA fingerprint).
|
|
1309
|
+
*
|
|
1310
|
+
* Retained for backward compatibility and constructor validation only. It no
|
|
1311
|
+
* longer takes part in the start-up self-check: that check compares against the
|
|
1312
|
+
* identity of the gateway this controller created and advertises, because the
|
|
1313
|
+
* self-signed FRP ingress gateway is pinned to the ingress CA fingerprint by
|
|
1314
|
+
* design, and that value deliberately differs from this one.
|
|
1315
|
+
*/
|
|
971
1316
|
readonly instanceId: string;
|
|
972
|
-
readonly createGateway: (origin: string) => Promise<MobileAccessGateway>;
|
|
1317
|
+
readonly createGateway: (origin: string, settings: FrpSettings) => Promise<MobileAccessGateway>;
|
|
973
1318
|
readonly onStatus?: (status: FrpStatus) => void;
|
|
974
1319
|
readonly verifyConfig?: (executable: string, configFile: string) => Promise<void>;
|
|
975
1320
|
readonly launchClient?: (executable: string, configFile: string) => ChildProcessWithoutNullStreams;
|
|
976
1321
|
readonly probeVhostExposure?: (serverAddress: string, port: number) => Promise<boolean>;
|
|
977
|
-
readonly probeDiscovery?: (
|
|
1322
|
+
readonly probeDiscovery?: (target: FrpDiscoveryProbeTarget, expectedInstanceId: string, signal: AbortSignal) => Promise<boolean>;
|
|
1323
|
+
/**
|
|
1324
|
+
* Resolve the CA the self-check must pin for the self-signed entry.
|
|
1325
|
+
*
|
|
1326
|
+
* Only the composing plugin knows where the ingress material lives, so the
|
|
1327
|
+
* trust anchor is injected instead of guessed here. Consulted solely for the
|
|
1328
|
+
* self-signed passthrough; the public-CA entry always keeps the system trust
|
|
1329
|
+
* store. A configured resolver that cannot provide the CA fails startup with
|
|
1330
|
+
* `frp_ingress_ca_invalid`; the system trust store must not mask that failure.
|
|
1331
|
+
*/
|
|
1332
|
+
readonly resolveDiscoveryTrustAnchor?: (settings: FrpSettings) => Promise<string | undefined>;
|
|
1333
|
+
/** Re-issue an expiring leaf and reload the live TLS listener without changing its CA. */
|
|
1334
|
+
readonly maintainIngressCertificate?: (settings: FrpSettings, gateway: MobileAccessGateway) => Promise<void>;
|
|
1335
|
+
/** Test seam for the maintenance timer; the product uses a twelve-hour interval. */
|
|
1336
|
+
readonly ingressCertificateCheckMs?: number;
|
|
978
1337
|
readonly startTimeoutMs?: number;
|
|
979
1338
|
readonly retryIntervalMs?: number;
|
|
980
1339
|
}
|
|
@@ -990,6 +1349,7 @@ declare class FrpController implements RemoteProviderController {
|
|
|
990
1349
|
private latest;
|
|
991
1350
|
private queue;
|
|
992
1351
|
private startupAbort;
|
|
1352
|
+
private ingressCertificateTimer;
|
|
993
1353
|
constructor(options: FrpControllerOptions);
|
|
994
1354
|
/** Restore the remembered FRP switch without changing LAN or other providers. */
|
|
995
1355
|
initialize(): Promise<void>;
|
|
@@ -1008,7 +1368,21 @@ declare class FrpController implements RemoteProviderController {
|
|
|
1008
1368
|
private enqueue;
|
|
1009
1369
|
private publish;
|
|
1010
1370
|
private start;
|
|
1371
|
+
/**
|
|
1372
|
+
* Derive the self-check target and trust anchor for the effective entry.
|
|
1373
|
+
*
|
|
1374
|
+
* The public-CA entry is reached on the saved origin itself: Caddy terminates
|
|
1375
|
+
* TLS on 443 with a publicly trusted certificate, so the probe must keep the
|
|
1376
|
+
* system trust store and the origin URL untouched. The self-signed entry is a
|
|
1377
|
+
* raw TCP passthrough on `publicPort` whose leaf chains to the ingress CA the
|
|
1378
|
+
* app pins from `pairingCaFile`; probing `publicOrigin` there would knock on
|
|
1379
|
+
* 443 — where nothing listens — with a chain the system cannot verify. Both
|
|
1380
|
+
* facts used to be implicit, and together they kept the channel out of `ready`
|
|
1381
|
+
* until `frp_start_timeout`.
|
|
1382
|
+
*/
|
|
1383
|
+
private discoveryCheck;
|
|
1011
1384
|
private waitForDiscovery;
|
|
1385
|
+
private scheduleIngressCertificateCheck;
|
|
1012
1386
|
private failGeneration;
|
|
1013
1387
|
private stop;
|
|
1014
1388
|
private stopProcessAndGateway;
|
|
@@ -1440,5 +1814,5 @@ declare function originGatewayConfig(template: ResolvedGatewayConfig, settings:
|
|
|
1440
1814
|
/** Mount the resident control route and its optional authenticated LAN gateway. */
|
|
1441
1815
|
declare function apply(ctx: Context, config: PluginConfig): Promise<void>;
|
|
1442
1816
|
//#endregion
|
|
1443
|
-
export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, type BlockedUpgradePathEntry, BlockedUpgradePathLog, BoundedRateLimiter, CLOUDFLARED_COMPONENT_RELEASE, CSRF_COOKIE, CSRF_HEADER, CloudflaredComponentManager, type CloudflaredComponentStatus, CloudflaredController, type CloudflaredControllerOptions, type CloudflaredState, type CloudflaredStatus, type CloudflaredTunnelMode, type CloudflaredTunnelSettings, type CloudflaredTunnelStatus, CloudflaredTunnelStore, Config, DEFAULT_ORIGIN_LISTEN_PORT, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceProbeResult, 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, OriginConfigStore, type OriginConfigurationStatus, OriginController, type OriginControllerOptions, type OriginSettings, type OriginState, type OriginStatus, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, REMOTE_PROVIDERS, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type SessionAuthorization, type SessionEndReason, type StoredDevice, TASK_EVENT_DEBOUNCE_MS, type TaskCompletionEvent, type TaskEventContext, TaskEventHub, type TaskEventSession, type TaskEventSink, type TaskEventWatcherOptions, type TaskTurnEvent, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, inject, isCloudflaredRegistration, isGloballyRoutableIpv4, isLoopbackAddress, mergeSavedCloudflaredTunnelSettings, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, originGatewayConfig, parseAuthority, parseCidr, parseCloudflaredOrigin, parseCloudflaredTunnelSettings, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseOriginSettings, parseRemoteProviderState, resolveAuthority, rewriteMobileIndex, validateCloudflaredTunnelHostname, validateCloudflaredTunnelPort, validateCloudflaredTunnelToken, validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateOriginAllowedCidrs, validateOriginListenHost, validateOriginListenPort, validateOriginPublicOrigin, validateWebSocketPath, watchTaskCompletions };
|
|
1817
|
+
export { AUTH_PREFIX, AccessController, type AccessControllerOptions, AccessError, type AuthoritySpec, type BlockedUpgradePathEntry, BlockedUpgradePathLog, BoundedRateLimiter, CERT_EXPIRING_DAYS, CLOUDFLARED_COMPONENT_RELEASE, CSRF_COOKIE, CSRF_HEADER, type CaddySiteOptions, type CertRenewalStatus, CloudflaredComponentManager, type CloudflaredComponentStatus, CloudflaredController, type CloudflaredControllerOptions, type CloudflaredState, type CloudflaredStatus, type CloudflaredTunnelMode, type CloudflaredTunnelSettings, type CloudflaredTunnelStatus, CloudflaredTunnelStore, Config, DEFAULT_ORIGIN_LISTEN_PORT, FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT, FRP_VHOST_HTTP_PORT, DEVICE_COOKIE, type DeviceProbeResult, type DeviceSnapshot, type DeviceStore, type DeviceSummary, type DisabledTlsConfig, EXTENSION_LIMITS, FRP_ATTACH_DISCOVERY_PATH, FRP_ATTACH_LOCAL_DECLARATION, FRP_ATTACH_SELF_SIGNED_DECLARATION, FRP_ATTACH_VPS_DECLARATION, FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_MARKER, FRP_CADDY_SNIPPET_PATH, FRP_COMPONENT_RELEASES, FRP_DEFAULT_PUBLIC_PORT, FRP_RESERVED_PORTS, type FrpAttachOptions, type FrpAttachPlan, type FrpAttachPlanLocal, type FrpAttachPlanStep, type FrpAttachStepId, type FrpAttachTemplate, type FrpAttachVpsParts, FrpComponentManager, type FrpComponentStatus, FrpConfigStore, type FrpConfigurationStatus, FrpController, type FrpControllerOptions, type FrpEntryTls, type FrpIngressCertificate, type FrpIngressPaths, type FrpIngressSelfCheck, 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, OriginConfigStore, type OriginConfigurationStatus, OriginController, type OriginControllerOptions, type OriginSettings, type OriginState, type OriginStatus, type PairingResult, type ParsedCidr, type PluginConfig, type ProvidedTlsConfig, REMOTE_PROVIDERS, type RemoteProvider, type RemoteProviderController, type RemoteProviderState, type RemoteProviderStatus, type RenewalResult, RequestTrustPolicy, type ResolvedGatewayConfig, SESSION_COOKIE, type ServerCertificateAuthority, type ServerCertificateFiles, type ServerCertificateTarget, type SessionAuthorization, type SessionEndReason, type StoredDevice, TASK_EVENT_DEBOUNCE_MS, type TaskCompletionEvent, type TaskEventContext, TaskEventHub, type TaskEventSession, type TaskEventSink, type TaskEventWatcherOptions, type TaskTurnEvent, type TlsConfig, WS_PATHS, WebSocketPathStore, addressAllowed, apply, assertExtensionId, configuredRemoteProvider, createCaddySite, createFrpAttachPlan, createFrpAttachTemplate, createFrpAttachTemplateParts, createFrpServerTemplate, createFrpcToml, createMobileAccessService, createRestrictedFrpServerTemplate, ensureFrpIngressCertificate, evaluateCertificateLifetime, frpAttachVpsParts, frpIngressPaths, frpIngressSelfCheck, inject, isCloudflaredRegistration, isFrpSelfSignedIngress, isGloballyRoutableIpv4, isLoopbackAddress, issueServerCertificate, mergeSavedCloudflaredTunnelSettings, mergeSavedFrpSettings, mergeSavedFrpTarget, name, normalizeWebSocketPaths, originGatewayConfig, parseAuthority, parseCidr, parseCloudflaredOrigin, parseCloudflaredTunnelSettings, parseControlFile, parseDeviceSnapshot, parseExtensionManifest, parseFrpSettings, parseGatewayConfig, parseMobileAccessControlState, parseOriginSettings, parseRemoteProviderState, probeOriginCertificate, readCertificateRenewal, resolveAuthority, resolveFrpEntryTls, resolveFrpMode, resolveFrpPublicPort, resolveFrpVhostHttpPort, rewriteMobileIndex, validateAttachSettings, validateCloudflaredTunnelHostname, validateCloudflaredTunnelPort, validateCloudflaredTunnelToken, validateFrpEntryTls, validateFrpMode, validateFrpPublicOrigin, validateFrpPublicPort, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, validateFrpVhostHttpPort, validateOriginAllowedCidrs, validateOriginListenHost, validateOriginListenPort, validateOriginPublicOrigin, validateWebSocketPath, watchTaskCompletions };
|
|
1444
1818
|
//# sourceMappingURL=index.d.mts.map
|