@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/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(" ");