@sanctuary-framework/mcp-server 0.10.1 → 0.10.2
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/dist/cli.cjs +100 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +100 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +44 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2871,6 +2871,24 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
|
|
|
2871
2871
|
private rateLimits;
|
|
2872
2872
|
/** Whether the dashboard is running in standalone mode (no MCP server) */
|
|
2873
2873
|
private _standaloneMode;
|
|
2874
|
+
/**
|
|
2875
|
+
* v0.10.2: when set, requests from loopback addresses (127.0.0.1 / ::1)
|
|
2876
|
+
* are treated as authenticated without requiring a Bearer token or
|
|
2877
|
+
* dashboard session cookie. Only the `startStandaloneDashboard` boot
|
|
2878
|
+
* path enables this, and ONLY after the supplied passphrase successfully
|
|
2879
|
+
* decrypts at least one stored identity — proving the caller already
|
|
2880
|
+
* holds the primary secret that protects every piece of Sanctuary state.
|
|
2881
|
+
*
|
|
2882
|
+
* Rationale: the dashboard auth token is a dashboard-access credential
|
|
2883
|
+
* layered on top of the master-key unlock. Once the operator has already
|
|
2884
|
+
* presented the passphrase on the command line (terminal-side auth), a
|
|
2885
|
+
* second login prompt in the auto-opened browser just trains users to
|
|
2886
|
+
* paste secrets into web forms — the exact habit Sanctuary exists to
|
|
2887
|
+
* discourage. Remote (non-loopback) callers still require the bearer
|
|
2888
|
+
* token, so this is a localhost-only ergonomics unlock, not a network
|
|
2889
|
+
* policy change.
|
|
2890
|
+
*/
|
|
2891
|
+
private _autoAuthLocalhost;
|
|
2874
2892
|
constructor(config: DashboardConfig);
|
|
2875
2893
|
/**
|
|
2876
2894
|
* Inject dependencies after construction.
|
|
@@ -2892,6 +2910,21 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
|
|
|
2892
2910
|
* Exposed via /api/status so the frontend can show an appropriate banner.
|
|
2893
2911
|
*/
|
|
2894
2912
|
setStandaloneMode(standalone: boolean): void;
|
|
2913
|
+
/**
|
|
2914
|
+
* v0.10.2: enable (or disable) the loopback auto-auth fast path. See
|
|
2915
|
+
* {@link _autoAuthLocalhost} for the rationale and threat model. Callers
|
|
2916
|
+
* should gate this on both (a) the dashboard host being a loopback
|
|
2917
|
+
* interface and (b) the master-key unlock having succeeded against
|
|
2918
|
+
* on-disk state.
|
|
2919
|
+
*/
|
|
2920
|
+
setAutoAuthLocalhost(enabled: boolean): void;
|
|
2921
|
+
/**
|
|
2922
|
+
* v0.10.2: is this request from a loopback interface? We treat the
|
|
2923
|
+
* standard IPv4/IPv6 loopback addresses plus the IPv4-mapped IPv6 form
|
|
2924
|
+
* as loopback so LAN clients never accidentally hit the unauthenticated
|
|
2925
|
+
* fast path even on hosts where the HTTP server binds 0.0.0.0.
|
|
2926
|
+
*/
|
|
2927
|
+
private isLoopbackRequest;
|
|
2895
2928
|
/**
|
|
2896
2929
|
* Start the HTTP(S) server for the dashboard.
|
|
2897
2930
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -2871,6 +2871,24 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
|
|
|
2871
2871
|
private rateLimits;
|
|
2872
2872
|
/** Whether the dashboard is running in standalone mode (no MCP server) */
|
|
2873
2873
|
private _standaloneMode;
|
|
2874
|
+
/**
|
|
2875
|
+
* v0.10.2: when set, requests from loopback addresses (127.0.0.1 / ::1)
|
|
2876
|
+
* are treated as authenticated without requiring a Bearer token or
|
|
2877
|
+
* dashboard session cookie. Only the `startStandaloneDashboard` boot
|
|
2878
|
+
* path enables this, and ONLY after the supplied passphrase successfully
|
|
2879
|
+
* decrypts at least one stored identity — proving the caller already
|
|
2880
|
+
* holds the primary secret that protects every piece of Sanctuary state.
|
|
2881
|
+
*
|
|
2882
|
+
* Rationale: the dashboard auth token is a dashboard-access credential
|
|
2883
|
+
* layered on top of the master-key unlock. Once the operator has already
|
|
2884
|
+
* presented the passphrase on the command line (terminal-side auth), a
|
|
2885
|
+
* second login prompt in the auto-opened browser just trains users to
|
|
2886
|
+
* paste secrets into web forms — the exact habit Sanctuary exists to
|
|
2887
|
+
* discourage. Remote (non-loopback) callers still require the bearer
|
|
2888
|
+
* token, so this is a localhost-only ergonomics unlock, not a network
|
|
2889
|
+
* policy change.
|
|
2890
|
+
*/
|
|
2891
|
+
private _autoAuthLocalhost;
|
|
2874
2892
|
constructor(config: DashboardConfig);
|
|
2875
2893
|
/**
|
|
2876
2894
|
* Inject dependencies after construction.
|
|
@@ -2892,6 +2910,21 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
|
|
|
2892
2910
|
* Exposed via /api/status so the frontend can show an appropriate banner.
|
|
2893
2911
|
*/
|
|
2894
2912
|
setStandaloneMode(standalone: boolean): void;
|
|
2913
|
+
/**
|
|
2914
|
+
* v0.10.2: enable (or disable) the loopback auto-auth fast path. See
|
|
2915
|
+
* {@link _autoAuthLocalhost} for the rationale and threat model. Callers
|
|
2916
|
+
* should gate this on both (a) the dashboard host being a loopback
|
|
2917
|
+
* interface and (b) the master-key unlock having succeeded against
|
|
2918
|
+
* on-disk state.
|
|
2919
|
+
*/
|
|
2920
|
+
setAutoAuthLocalhost(enabled: boolean): void;
|
|
2921
|
+
/**
|
|
2922
|
+
* v0.10.2: is this request from a loopback interface? We treat the
|
|
2923
|
+
* standard IPv4/IPv6 loopback addresses plus the IPv4-mapped IPv6 form
|
|
2924
|
+
* as loopback so LAN clients never accidentally hit the unauthenticated
|
|
2925
|
+
* fast path even on hosts where the HTTP server binds 0.0.0.0.
|
|
2926
|
+
*/
|
|
2927
|
+
private isLoopbackRequest;
|
|
2895
2928
|
/**
|
|
2896
2929
|
* Start the HTTP(S) server for the dashboard.
|
|
2897
2930
|
*/
|
package/dist/index.js
CHANGED
|
@@ -8700,6 +8700,24 @@ var DashboardApprovalChannel = class {
|
|
|
8700
8700
|
rateLimits = /* @__PURE__ */ new Map();
|
|
8701
8701
|
/** Whether the dashboard is running in standalone mode (no MCP server) */
|
|
8702
8702
|
_standaloneMode = false;
|
|
8703
|
+
/**
|
|
8704
|
+
* v0.10.2: when set, requests from loopback addresses (127.0.0.1 / ::1)
|
|
8705
|
+
* are treated as authenticated without requiring a Bearer token or
|
|
8706
|
+
* dashboard session cookie. Only the `startStandaloneDashboard` boot
|
|
8707
|
+
* path enables this, and ONLY after the supplied passphrase successfully
|
|
8708
|
+
* decrypts at least one stored identity — proving the caller already
|
|
8709
|
+
* holds the primary secret that protects every piece of Sanctuary state.
|
|
8710
|
+
*
|
|
8711
|
+
* Rationale: the dashboard auth token is a dashboard-access credential
|
|
8712
|
+
* layered on top of the master-key unlock. Once the operator has already
|
|
8713
|
+
* presented the passphrase on the command line (terminal-side auth), a
|
|
8714
|
+
* second login prompt in the auto-opened browser just trains users to
|
|
8715
|
+
* paste secrets into web forms — the exact habit Sanctuary exists to
|
|
8716
|
+
* discourage. Remote (non-loopback) callers still require the bearer
|
|
8717
|
+
* token, so this is a localhost-only ergonomics unlock, not a network
|
|
8718
|
+
* policy change.
|
|
8719
|
+
*/
|
|
8720
|
+
_autoAuthLocalhost = false;
|
|
8703
8721
|
constructor(config) {
|
|
8704
8722
|
this.config = config;
|
|
8705
8723
|
this.authToken = config.auth_token;
|
|
@@ -8735,6 +8753,26 @@ var DashboardApprovalChannel = class {
|
|
|
8735
8753
|
setStandaloneMode(standalone) {
|
|
8736
8754
|
this._standaloneMode = standalone;
|
|
8737
8755
|
}
|
|
8756
|
+
/**
|
|
8757
|
+
* v0.10.2: enable (or disable) the loopback auto-auth fast path. See
|
|
8758
|
+
* {@link _autoAuthLocalhost} for the rationale and threat model. Callers
|
|
8759
|
+
* should gate this on both (a) the dashboard host being a loopback
|
|
8760
|
+
* interface and (b) the master-key unlock having succeeded against
|
|
8761
|
+
* on-disk state.
|
|
8762
|
+
*/
|
|
8763
|
+
setAutoAuthLocalhost(enabled) {
|
|
8764
|
+
this._autoAuthLocalhost = enabled;
|
|
8765
|
+
}
|
|
8766
|
+
/**
|
|
8767
|
+
* v0.10.2: is this request from a loopback interface? We treat the
|
|
8768
|
+
* standard IPv4/IPv6 loopback addresses plus the IPv4-mapped IPv6 form
|
|
8769
|
+
* as loopback so LAN clients never accidentally hit the unauthenticated
|
|
8770
|
+
* fast path even on hosts where the HTTP server binds 0.0.0.0.
|
|
8771
|
+
*/
|
|
8772
|
+
isLoopbackRequest(req) {
|
|
8773
|
+
const addr = this.getRemoteAddr(req);
|
|
8774
|
+
return addr === "127.0.0.1" || addr === "::1" || addr === "localhost";
|
|
8775
|
+
}
|
|
8738
8776
|
/**
|
|
8739
8777
|
* Start the HTTP(S) server for the dashboard.
|
|
8740
8778
|
*/
|
|
@@ -8884,6 +8922,9 @@ var DashboardApprovalChannel = class {
|
|
|
8884
8922
|
*/
|
|
8885
8923
|
checkAuth(req, url, res) {
|
|
8886
8924
|
if (!this.authToken) return true;
|
|
8925
|
+
if (this._autoAuthLocalhost && this.isLoopbackRequest(req)) {
|
|
8926
|
+
return true;
|
|
8927
|
+
}
|
|
8887
8928
|
const authHeader = req.headers.authorization;
|
|
8888
8929
|
if (authHeader) {
|
|
8889
8930
|
const parts = authHeader.split(" ");
|
|
@@ -8909,6 +8950,9 @@ var DashboardApprovalChannel = class {
|
|
|
8909
8950
|
*/
|
|
8910
8951
|
isAuthenticated(req, url) {
|
|
8911
8952
|
if (!this.authToken) return true;
|
|
8953
|
+
if (this._autoAuthLocalhost && this.isLoopbackRequest(req)) {
|
|
8954
|
+
return true;
|
|
8955
|
+
}
|
|
8912
8956
|
const authHeader = req.headers.authorization;
|
|
8913
8957
|
if (authHeader) {
|
|
8914
8958
|
const parts = authHeader.split(" ");
|