shadok-ai 0.17.37 → 0.17.39

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 CHANGED
@@ -161,7 +161,10 @@ Enter to skip; you can add it later from the web UI).
161
161
  `http://localhost:PORT/…`, which your browser cannot reach when the agents run
162
162
  in a container or on a remote box. Paste that failed address under *Finish a
163
163
  sign-in* in the Secrets panel (`POST /oauth-relay`, web UI only): the cockpit
164
- opens it on the agents' machine. Loopback http addresses with a port only.
164
+ opens it on the agents' machine. Loopback http addresses with a port only,
165
+ and only a callback (`code=`, `state=` or `error=` in the query); the
166
+ cockpit's own ports and well-known local services (debuggers, Docker's API,
167
+ databases) are refused, and only the listener's HTTP status comes back.
165
168
  - **Scheduled prompts** — give a channel a recurring prompt (every N minutes, or
166
169
  daily at HH:MM in a time zone you choose) for monitoring and reporting. Each
167
170
  schedule can carry a **deterministic guard command** that runs *without the
@@ -365,8 +368,14 @@ Enter to skip; you can add it later from the web UI).
365
368
  a profile edit that bumped no version still does. A `↻` lights up on the agent
366
369
  (hover for the reasons) and the **version menu** shows *Reload N agents to
367
370
  apply changes*; a reload respawns each one in place, keeping its history.
368
- Agents started before a given update stay on the old context until reloaded —
369
- this is how you spot the ones still running it.
371
+ **You don't have to click it**: the cockpit applies it by itself as soon as the
372
+ agent has nothing to lose — no turn running, no question waiting, nothing in
373
+ its input box, no background shell or monitor, no child notification queued —
374
+ and has been quiet for two minutes (the ↻ tooltip then says so).
375
+ One agent at a time, no nudge afterwards, and at most once per 30 minutes per
376
+ agent so a change that does not stick cannot loop. A message you send while
377
+ the respawn runs waits a few seconds for it instead of being refused. Clicking
378
+ still reloads at once; `SHADOK_AUTO_RELOAD=0` turns the automatic part off.
370
379
  - **Phone layout** — the cockpit is a fixed chassis that never pans sideways,
371
380
  sized on the *visual* viewport so the composer stays clear of the browser's
372
381
  own bar and, when the keyboard opens, sits right above it (the instrument bar
@@ -705,6 +714,38 @@ the same-origin policy, so without that check any page you happen to visit could
705
714
  drive your agents. Behind a reverse proxy that rewrites `Host`, list the public
706
715
  origin in `SHADOK_ORIGINS`.
707
716
 
717
+ **Which host names it answers (DNS rebinding).** A page on `evil.com` can
718
+ re-point its own name at `127.0.0.1`; its requests then carry `Origin` *and*
719
+ `Host` `evil.com:3789` and look same-origin. So the server also checks the
720
+ `Host` header, on every request and on the WebSocket upgrade:
721
+
722
+ - **No password** (the local default): only `localhost` / `*.localhost`, any IP
723
+ address, and this machine's own name (`hostname`, `hostname.local`) are
724
+ answered, on any port. Anything else gets `403 host not allowed` and one log
725
+ line. If you really reach a password-less cockpit through another name (an
726
+ `/etc/hosts` alias, a same-host proxy), add it to `SHADOK_ALLOWED_HOSTS`.
727
+ - **With a password**: every `Host` is answered, as before — a rebound page
728
+ holds no cookie for your cockpit, so it is a stranger at the login page. This
729
+ is what keeps a container behind nginx/Cloudflare on its own domain working
730
+ with no change. Setting `SHADOK_ALLOWED_HOSTS` tightens it to that list
731
+ (loopback names and IPs always stay allowed — agents call `127.0.0.1`).
732
+
733
+ `SHADOK_ALLOWED_HOSTS` is comma-separated: names, `host:port` or whole origins
734
+ (the port is ignored), `.example.com` for a domain and its subdomains, `*` to
735
+ switch the check off. The hosts in `SHADOK_ORIGINS` are accepted too.
736
+
737
+ **Sign-in attempts are limited.** A failed `POST /login` is counted against the
738
+ caller's address (10 per 15 minutes) and against the account (20 per 15
739
+ minutes, from all addresses together); past that the answer is `429` with a
740
+ `Retry-After`, before any password is checked. Enrollment codes are counted the
741
+ same way. An unknown user name costs the server exactly what a real one does,
742
+ so the timing says nothing about which accounts exist. The counters live in
743
+ memory: a restart clears them. Behind a proxy the address is the one the proxy
744
+ appended last to `X-Forwarded-For` — trusted only when the proxy connects from
745
+ this machine or a private range (the Docker bridge); a proxy that sends no
746
+ `X-Forwarded-For` puts every visitor in one address bucket, so ten wrong
747
+ passwords from anyone lock the login for everyone for 15 minutes.
748
+
708
749
  ### Behind TLS (nginx, Caddy…)
709
750
 
710
751
  Serving the cockpit over HTTPS works, with one requirement: **the proxy must
@@ -721,6 +762,7 @@ location / {
721
762
  proxy_set_header Connection "upgrade";
722
763
  proxy_set_header Host $host;
723
764
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # see below
765
+ proxy_set_header X-Forwarded-Proto $scheme; # Secure cookies
724
766
  client_max_body_size 50m; # match the server's paste limit
725
767
  }
726
768
  ```
@@ -734,6 +776,14 @@ server the request was relayed. Without it, requests through a same-host proxy
734
776
  look local. (A proxy on another host, or nginx in front of a Docker container,
735
777
  is already seen as the network.)
736
778
 
779
+ The same header is what the sign-in limiter keys on (see "Exposing it beyond
780
+ this machine").
781
+
782
+ **Secure cookies.** With `X-Forwarded-Proto: https` from a proxy on this machine
783
+ or a private range (Docker bridge), the session cookies are set `Secure`, so a
784
+ browser never sends them over plain http. Without that header they are set as
785
+ before.
786
+
737
787
  The client picks `wss://` on its own when the page is HTTPS, so there is nothing
738
788
  to configure on that side.
739
789
 
@@ -947,9 +997,12 @@ machine, which silently shifts every daily prompt on a server running in UTC.
947
997
  | `PORT` | HTTP/WS port |
948
998
  | `SHADOK_HOST` | interface to bind (default `127.0.0.1`, this machine only) |
949
999
  | `SHADOK_GUI_PASSWORD` | require a password for the GUI — overrides a password saved by `--password` |
950
- | `SHADOK_ORIGINS` | extra browser origins allowed, comma-separated (reverse proxy) |
1000
+ | `SHADOK_ORIGINS` | extra browser origins allowed, comma-separated (reverse proxy); their hosts also pass the Host check |
1001
+ | `SHADOK_ALLOWED_HOSTS` | host names the cockpit answers besides its own (DNS-rebinding guard); with a password, setting it makes the check strict. `*` disables it |
951
1002
  | `SHADOK_TMUX=0` | force the node-pty transport instead of tmux |
952
1003
  | `SHADOK_IDLE_MIN` | minutes with no client before a session is reclaimed (60) |
1004
+ | `SHADOK_AUTO_RELOAD=0` | don't apply a pending "reload to apply" by itself — leave it to the ↻ click |
1005
+ | `SHADOK_AUTO_RELOAD_IDLE_SEC` | how long an agent must be quiet before that automatic reload (120) |
953
1006
  | `SHADOK_PERMISSION_MODE` | mode new agents start in (default `acceptEdits`) |
954
1007
  | `SHADOK_AUTOUPDATE` | fallback only — the GUI setting wins once used |
955
1008
  | `SHADOK_PILOT_PROMPT=0` | don't inject the cockpit system prompt |
@@ -55,6 +55,19 @@ export declare function saveAccounts(list: Account[]): void;
55
55
  * not produce the same hash and cannot be spotted as identical. */
56
56
  export declare function hashPassword(plain: string): string;
57
57
  export declare function verifyPassword(plain: string, hash: string): boolean;
58
+ /**
59
+ * The async twins, for the request path. `scryptSync` runs ON the event loop:
60
+ * every sign-in attempt froze every agent's I/O for the length of a hash, and a
61
+ * guesser could hold the server down that way. `scrypt` runs on the libuv pool.
62
+ */
63
+ export declare function hashPasswordAsync(plain: string): Promise<string>;
64
+ export declare function verifyPasswordAsync(plain: string, hash: string): Promise<boolean>;
65
+ /**
66
+ * The check an UNKNOWN account (or an invitation not yet redeemed) gets: the
67
+ * same scrypt as a real one, always false. Answering such a name at once while
68
+ * a real one took a hash's time told a guesser which accounts exist.
69
+ */
70
+ export declare function burnPasswordCheck(plain: string): Promise<false>;
58
71
  /**
59
72
  * Who may change which account. Pure, so the whole policy is one testable
60
73
  * place rather than a condition repeated at three endpoints.
package/dist/accounts.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { createHmac, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
4
+ import { createHmac, randomBytes, scrypt, scryptSync, timingSafeEqual } from "node:crypto";
5
5
  import { instanceKey } from "./paths.js";
6
6
  /** The account that lives in SHADOK_GUI_PASSWORD, never in the file. */
7
7
  export const BOOTSTRAP_ADMIN = "admin";
@@ -46,6 +46,47 @@ export function verifyPassword(plain, hash) {
46
46
  return false;
47
47
  }
48
48
  }
49
+ function scryptAsync(plain, salt, len) {
50
+ return new Promise((resolve, reject) => scrypt(plain, salt, len, (err, key) => (err ? reject(err) : resolve(key))));
51
+ }
52
+ /**
53
+ * The async twins, for the request path. `scryptSync` runs ON the event loop:
54
+ * every sign-in attempt froze every agent's I/O for the length of a hash, and a
55
+ * guesser could hold the server down that way. `scrypt` runs on the libuv pool.
56
+ */
57
+ export async function hashPasswordAsync(plain) {
58
+ const salt = randomBytes(16);
59
+ const key = await scryptAsync(plain, salt, 64);
60
+ return `scrypt$${salt.toString("hex")}$${key.toString("hex")}`;
61
+ }
62
+ export async function verifyPasswordAsync(plain, hash) {
63
+ const parts = String(hash ?? "").split("$");
64
+ if (parts.length !== 3 || parts[0] !== "scrypt")
65
+ return false;
66
+ try {
67
+ const salt = Buffer.from(parts[1], "hex");
68
+ const want = Buffer.from(parts[2], "hex");
69
+ if (!salt.length || !want.length)
70
+ return false;
71
+ const got = await scryptAsync(plain, salt, want.length);
72
+ return got.length === want.length && timingSafeEqual(got, want);
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ }
78
+ /** A hash no password matches (the derived half is all zeros), same shape and
79
+ * cost as a real one. */
80
+ const DUMMY_HASH = `scrypt$${"5a".repeat(16)}$${"00".repeat(64)}`;
81
+ /**
82
+ * The check an UNKNOWN account (or an invitation not yet redeemed) gets: the
83
+ * same scrypt as a real one, always false. Answering such a name at once while
84
+ * a real one took a hash's time told a guesser which accounts exist.
85
+ */
86
+ export async function burnPasswordCheck(plain) {
87
+ await verifyPasswordAsync(plain, DUMMY_HASH);
88
+ return false;
89
+ }
49
90
  /**
50
91
  * Who may change which account. Pure, so the whole policy is one testable
51
92
  * place rather than a condition repeated at three endpoints.
@@ -1 +1 @@
1
- {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Auto-reload: apply a pending "reload to apply" by itself, at a moment that
3
+ * cuts nothing.
4
+ *
5
+ * The cockpit already KNOWS when a running agent is behind what a fresh spawn
6
+ * would give it (`stalenessReasons`: prompt/guardrails/skills/secrets changed,
7
+ * auth cookie past its week, Claude Code binary updated — plus a profile change
8
+ * stored "at next reload"). Until now it only painted a ↻ badge and waited for a
9
+ * human to click it, so a profile edit or a shadok update sat unapplied on every
10
+ * agent nobody happened to look at.
11
+ *
12
+ * A reload is a `--resume`: the conversation survives, but the PROCESS does not.
13
+ * Everything that lives only in that process dies with it — a turn in flight, a
14
+ * question on screen, text typed in the TUI's input box, a background shell or
15
+ * monitor, a parent notification waiting to be delivered. So the rule is not
16
+ * "reload when idle" but "reload when there is provably nothing to lose", and
17
+ * every condition below names one of those losses.
18
+ *
19
+ * The quiet window is the soft half: an agent that JUST finished is the one a
20
+ * human is most likely about to answer. Waiting a couple of minutes past the
21
+ * last activity keeps the reload out of a live exchange. (A prompt that arrives
22
+ * anyway while the respawn runs is held until it is ready — see the prompt
23
+ * handler — so the worst case is a few seconds of delay, never a lost message.)
24
+ *
25
+ * The backoff is the safety net: if the reasons survive a reload (a fingerprint
26
+ * that is not deterministic, a version probe that flaps), reloading again every
27
+ * two minutes would be a respawn loop. One automatic attempt per window, then
28
+ * the badge stays for a human to look at.
29
+ */
30
+ export interface AutoReloadInput {
31
+ /** Is the feature on for this instance? */
32
+ enabled: boolean;
33
+ /** How many reasons the agent is behind (staleness + a stored profile gap). */
34
+ pendingReasons: number;
35
+ /** A turn is running, or the server is driving one (`busy`). */
36
+ busy: boolean;
37
+ /** The pane itself shows work (spinner) — covers a turn nobody started from here. */
38
+ working: boolean;
39
+ /** A prompt is being typed into the TUI right now. */
40
+ submitting: boolean;
41
+ /** A restart is already swapping this agent's process. */
42
+ restarting: boolean;
43
+ /** The pilot's process has exited (nothing to reload; the resume path owns it). */
44
+ exited: boolean;
45
+ /** A question/permission dialog is on screen, waiting for an answer. */
46
+ dialogOpen: boolean;
47
+ /** What the TUI input box holds — text a respawn would discard. */
48
+ inputBox: string;
49
+ /** Background shells / monitors the pane reports running. */
50
+ shells: number;
51
+ monitors: number;
52
+ /** Child-agent notifications queued for this agent as a parent. */
53
+ inboxPending: number;
54
+ /** An auto-retry of a failed turn is scheduled. */
55
+ retryPending: boolean;
56
+ /** Milliseconds since the last thing that happened on this agent. */
57
+ idleMs: number;
58
+ /** How long it must have been quiet. */
59
+ quietMs: number;
60
+ /** Milliseconds since the last AUTOMATIC reload of this agent (Infinity if never). */
61
+ sinceLastAutoMs: number;
62
+ /** Minimum gap between two automatic reloads of the same agent. */
63
+ backoffMs: number;
64
+ }
65
+ export type AutoReloadVerdict = {
66
+ reload: true;
67
+ } | {
68
+ reload: false;
69
+ why: string;
70
+ };
71
+ /** Pure: may this agent be reloaded right now without cutting anything? */
72
+ export declare function autoReloadVerdict(i: AutoReloadInput): AutoReloadVerdict;
73
+ /** `SHADOK_AUTO_RELOAD=0` turns it off; anything else (or unset) leaves it on. */
74
+ export declare function autoReloadEnabled(env: string | undefined): boolean;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Auto-reload: apply a pending "reload to apply" by itself, at a moment that
3
+ * cuts nothing.
4
+ *
5
+ * The cockpit already KNOWS when a running agent is behind what a fresh spawn
6
+ * would give it (`stalenessReasons`: prompt/guardrails/skills/secrets changed,
7
+ * auth cookie past its week, Claude Code binary updated — plus a profile change
8
+ * stored "at next reload"). Until now it only painted a ↻ badge and waited for a
9
+ * human to click it, so a profile edit or a shadok update sat unapplied on every
10
+ * agent nobody happened to look at.
11
+ *
12
+ * A reload is a `--resume`: the conversation survives, but the PROCESS does not.
13
+ * Everything that lives only in that process dies with it — a turn in flight, a
14
+ * question on screen, text typed in the TUI's input box, a background shell or
15
+ * monitor, a parent notification waiting to be delivered. So the rule is not
16
+ * "reload when idle" but "reload when there is provably nothing to lose", and
17
+ * every condition below names one of those losses.
18
+ *
19
+ * The quiet window is the soft half: an agent that JUST finished is the one a
20
+ * human is most likely about to answer. Waiting a couple of minutes past the
21
+ * last activity keeps the reload out of a live exchange. (A prompt that arrives
22
+ * anyway while the respawn runs is held until it is ready — see the prompt
23
+ * handler — so the worst case is a few seconds of delay, never a lost message.)
24
+ *
25
+ * The backoff is the safety net: if the reasons survive a reload (a fingerprint
26
+ * that is not deterministic, a version probe that flaps), reloading again every
27
+ * two minutes would be a respawn loop. One automatic attempt per window, then
28
+ * the badge stays for a human to look at.
29
+ */
30
+ /** Pure: may this agent be reloaded right now without cutting anything? */
31
+ export function autoReloadVerdict(i) {
32
+ const no = (why) => ({ reload: false, why });
33
+ if (!i.enabled)
34
+ return no("disabled");
35
+ if (i.pendingReasons <= 0)
36
+ return no("up to date");
37
+ if (i.exited)
38
+ return no("process exited");
39
+ if (i.restarting)
40
+ return no("already restarting");
41
+ if (i.busy || i.working)
42
+ return no("working");
43
+ if (i.submitting)
44
+ return no("a prompt is being typed");
45
+ if (i.dialogOpen)
46
+ return no("waiting on a question");
47
+ if (i.inputBox.trim())
48
+ return no("text in the input box");
49
+ if (i.shells > 0 || i.monitors > 0)
50
+ return no("background task running");
51
+ if (i.inboxPending > 0)
52
+ return no("notifications queued");
53
+ if (i.retryPending)
54
+ return no("auto-retry scheduled");
55
+ if (i.idleMs < i.quietMs)
56
+ return no("recently active");
57
+ if (i.sinceLastAutoMs < i.backoffMs)
58
+ return no("auto-reloaded recently");
59
+ return { reload: true };
60
+ }
61
+ /** `SHADOK_AUTO_RELOAD=0` turns it off; anything else (or unset) leaves it on. */
62
+ export function autoReloadEnabled(env) {
63
+ return env === undefined || !/^(0|false|off|no)$/i.test(env.trim());
64
+ }
65
+ //# sourceMappingURL=auto-reload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-reload.js","sourceRoot":"","sources":["../src/auto-reload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAwCH,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,CAAkB;IAClD,MAAM,EAAE,GAAG,CAAC,GAAW,EAAqB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACxE,IAAI,CAAC,CAAC,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,CAAC,cAAc,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC,oBAAoB,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC,yBAAyB,CAAC,CAAC;IACvD,IAAI,CAAC,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC,uBAAuB,CAAC,CAAC;IACrD,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,uBAAuB,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC,yBAAyB,CAAC,CAAC;IACzE,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC,YAAY;QAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,CAAC;IACtD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC;IACvD,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC,wBAAwB,CAAC,CAAC;IACzE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,OAAO,GAAG,KAAK,SAAS,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Failed sign-in attempts, counted per address AND per account, in memory.
3
+ *
4
+ * `POST /login` used to accept guesses as fast as they came: with a password
5
+ * set, the password is the door to a shell on the host, and nothing slowed a
6
+ * guesser down. Two buckets, because each alone fails: per address alone lets
7
+ * a guesser rotating addresses hammer one account; per account alone lets one
8
+ * guesser lock every named user out. The account bucket is therefore the larger
9
+ * one — it caps a distributed attack without making a lockout of someone else
10
+ * cheap.
11
+ *
12
+ * A blocked attempt is refused BEFORE the hash is computed: a flood costs the
13
+ * server nothing past the limit. Memory is bounded (`maxKeys`) because the
14
+ * account key is whatever name the guesser typed. A restart forgets everything,
15
+ * deliberately — a limiter that could lock the owner out across restarts would
16
+ * be worse than one a restart resets. Pure over an injected clock — tested.
17
+ */
18
+ export type LimitConfig = {
19
+ windowMs: number;
20
+ maxPerIp: number;
21
+ maxPerAccount: number;
22
+ maxKeys?: number;
23
+ };
24
+ export declare const LOGIN_LIMITS: LimitConfig;
25
+ export type LimitVerdict = {
26
+ ok: true;
27
+ } | {
28
+ ok: false;
29
+ retryAfterMs: number;
30
+ };
31
+ /** The buckets one attempt is charged to. A blank user IS the admin. */
32
+ export declare function loginKeys(address: string, user: string): string[];
33
+ export declare class AttemptLimiter {
34
+ private cfg;
35
+ private now;
36
+ private failures;
37
+ constructor(cfg: LimitConfig, now?: () => number);
38
+ private live;
39
+ private max;
40
+ check(keys: string[]): LimitVerdict;
41
+ fail(keys: string[]): void;
42
+ /** A correct password clears the ACCOUNT's failures (whoever caused them),
43
+ * never the address's: a guesser holding one valid account must not be able
44
+ * to reset their own address bucket between guesses at another. */
45
+ succeed(keys: string[]): void;
46
+ size(): number;
47
+ private bound;
48
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Failed sign-in attempts, counted per address AND per account, in memory.
3
+ *
4
+ * `POST /login` used to accept guesses as fast as they came: with a password
5
+ * set, the password is the door to a shell on the host, and nothing slowed a
6
+ * guesser down. Two buckets, because each alone fails: per address alone lets
7
+ * a guesser rotating addresses hammer one account; per account alone lets one
8
+ * guesser lock every named user out. The account bucket is therefore the larger
9
+ * one — it caps a distributed attack without making a lockout of someone else
10
+ * cheap.
11
+ *
12
+ * A blocked attempt is refused BEFORE the hash is computed: a flood costs the
13
+ * server nothing past the limit. Memory is bounded (`maxKeys`) because the
14
+ * account key is whatever name the guesser typed. A restart forgets everything,
15
+ * deliberately — a limiter that could lock the owner out across restarts would
16
+ * be worse than one a restart resets. Pure over an injected clock — tested.
17
+ */
18
+ export const LOGIN_LIMITS = {
19
+ windowMs: 15 * 60_000,
20
+ maxPerIp: 10,
21
+ maxPerAccount: 20,
22
+ maxKeys: 10_000,
23
+ };
24
+ /** The buckets one attempt is charged to. A blank user IS the admin. */
25
+ export function loginKeys(address, user) {
26
+ return [`ip:${address}`, `acct:${user || "admin"}`];
27
+ }
28
+ export class AttemptLimiter {
29
+ cfg;
30
+ now;
31
+ failures = new Map();
32
+ constructor(cfg, now = Date.now) {
33
+ this.cfg = cfg;
34
+ this.now = now;
35
+ }
36
+ live(key) {
37
+ const cut = this.now() - this.cfg.windowMs;
38
+ const kept = (this.failures.get(key) ?? []).filter((t) => t > cut);
39
+ if (kept.length)
40
+ this.failures.set(key, kept);
41
+ else
42
+ this.failures.delete(key);
43
+ return kept;
44
+ }
45
+ max(key) {
46
+ return key.startsWith("ip:") ? this.cfg.maxPerIp : this.cfg.maxPerAccount;
47
+ }
48
+ check(keys) {
49
+ let wait = 0;
50
+ for (const k of keys) {
51
+ const f = this.live(k);
52
+ const max = this.max(k);
53
+ if (f.length >= max)
54
+ wait = Math.max(wait, f[f.length - max] + this.cfg.windowMs - this.now());
55
+ }
56
+ return wait > 0 ? { ok: false, retryAfterMs: wait } : { ok: true };
57
+ }
58
+ fail(keys) {
59
+ const t = this.now();
60
+ for (const k of keys) {
61
+ const f = this.live(k);
62
+ f.push(t);
63
+ // Re-inserted at the end, so Map order is "least recently failed first".
64
+ this.failures.delete(k);
65
+ this.failures.set(k, f.slice(-this.max(k)));
66
+ }
67
+ this.bound();
68
+ }
69
+ /** A correct password clears the ACCOUNT's failures (whoever caused them),
70
+ * never the address's: a guesser holding one valid account must not be able
71
+ * to reset their own address bucket between guesses at another. */
72
+ succeed(keys) {
73
+ for (const k of keys)
74
+ if (!k.startsWith("ip:"))
75
+ this.failures.delete(k);
76
+ }
77
+ size() {
78
+ return this.failures.size;
79
+ }
80
+ bound() {
81
+ const cap = this.cfg.maxKeys ?? Infinity;
82
+ if (this.failures.size <= cap)
83
+ return;
84
+ for (const k of [...this.failures.keys()])
85
+ this.live(k);
86
+ while (this.failures.size > cap)
87
+ this.failures.delete(this.failures.keys().next().value);
88
+ }
89
+ }
90
+ //# sourceMappingURL=login-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-limit.js","sourceRoot":"","sources":["../src/login-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,CAAC,MAAM,YAAY,GAAgB;IACvC,QAAQ,EAAE,EAAE,GAAG,MAAM;IACrB,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,MAAM;CAChB,CAAC;AAIF,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,IAAY;IACrD,OAAO,CAAC,MAAM,OAAO,EAAE,EAAE,QAAQ,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,OAAO,cAAc;IAIf,GAAG;IACH,GAAG;IAJL,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE/C,YACU,GAAgB,EAChB,GAAG,GAAiB,IAAI,CAAC,GAAG;mBAD5B,GAAG;mBACH,GAAG;IACV,CAAC;IAEI,IAAI,CAAC,GAAW;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3C,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QACnE,IAAI,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;;YACzC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,GAAG,CAAC,GAAW;QACrB,OAAO,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,IAAc;QAClB,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;gBAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACjG,CAAC;QACD,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACrE,CAAC;IAED,IAAI,CAAC,IAAc;QACjB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACV,yEAAyE;YACzE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED;;wEAEoE;IACpE,OAAO,CAAC,IAAc;QACpB,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAEO,KAAK;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC;QACzC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG;YAAE,OAAO;QACtC,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG;YAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;IACrG,CAAC;CACF"}
package/dist/net.d.ts CHANGED
@@ -89,3 +89,61 @@ export declare function browserOrigin(origin: string | undefined, host: string |
89
89
  * Pure — unit tested.
90
90
  */
91
91
  export declare function isLocalCaller(remoteAddress: string | undefined, headers: Record<string, unknown>): boolean;
92
+ /**
93
+ * The hostname a `Host` header names, lowercased, port and IPv6 brackets
94
+ * stripped — or null when it is not a plain host (spaces, userinfo, a path).
95
+ */
96
+ export declare function hostNameOf(host: string): string | null;
97
+ /**
98
+ * `SHADOK_ALLOWED_HOSTS` (or the hosts of `SHADOK_ORIGINS`): comma-separated
99
+ * names, `host:port`, or whole origins — reduced to the bare hostname. A
100
+ * leading dot (`.example.com`) also matches every subdomain; `*` disables the
101
+ * check altogether.
102
+ */
103
+ export declare function parseAllowedHosts(raw: string | undefined): string[];
104
+ export type HostPolicy = {
105
+ /** A GUI password is set: a rebinding page gets no cookie, so it gets nothing. */
106
+ passwordSet: boolean;
107
+ /** `SHADOK_ALLOWED_HOSTS` — setting it ALSO turns the strict check on under a password. */
108
+ allowedHosts: string[];
109
+ /** Hosts of `SHADOK_ORIGINS` — accepted, but they never turn strictness on. */
110
+ originHosts: string[];
111
+ /** This machine's own name(s) (`os.hostname()`): no attacker can serve a page on it. */
112
+ machineNames: string[];
113
+ };
114
+ /**
115
+ * May a request naming this `Host` be served? The defence against DNS
116
+ * rebinding, which `originAllowed` cannot provide: a page on `evil.com` that
117
+ * re-points its own name at 127.0.0.1 sends `Origin: http://evil.com:3789` AND
118
+ * `Host: evil.com:3789` — same-origin by every measure — and, with no password
119
+ * (the local default, where everything is the admin), drives the agents.
120
+ *
121
+ * Rebinding only ever produces a DOMAIN NAME the attacker controls, so the
122
+ * strict rule accepts what such a page cannot be: an IP literal (a browser on
123
+ * an IP sends that IP), `localhost` and `*.localhost` (resolved to loopback by
124
+ * the browser itself, RFC 6761), this machine's own name, and the lists.
125
+ *
126
+ * Strict only when it is NEEDED, so no deployment that exists today breaks:
127
+ * with a password the cookie is bound to the attacker's origin and a rebound
128
+ * page is just an unauthenticated stranger — every Host passes, as before,
129
+ * unless `SHADOK_ALLOWED_HOSTS` asks to tighten. A missing Host is a
130
+ * non-browser client (browsers always send one) and passes, like a missing
131
+ * Origin (invariant 11). Pure — unit tested.
132
+ */
133
+ export declare function hostHeaderAllowed(host: string | undefined, p: HostPolicy): boolean;
134
+ /** What a refused Host is told — names the knob, since a lockout must be fixable. */
135
+ export declare function hostRefusal(host: string): string;
136
+ /**
137
+ * The address a login attempt is charged to. The socket's, unless the socket is
138
+ * a trusted hop (loopback, or a private range — the Docker bridge an nginx on
139
+ * the host connects from) carrying `X-Forwarded-For`: then the LAST entry,
140
+ * the one OUR proxy appended (`$proxy_add_x_forwarded_for`). Everything before
141
+ * it is whatever the client claimed and is never trusted. Pure — unit tested.
142
+ */
143
+ export declare function clientAddress(remoteAddress: string | undefined, headers: Record<string, unknown>): string;
144
+ /**
145
+ * Did the browser reach us over HTTPS? A TLS socket, or a trusted hop saying
146
+ * so in `X-Forwarded-Proto` (first value: the outermost proxy's). Decides the
147
+ * cookies' `Secure` flag. Pure — unit tested.
148
+ */
149
+ export declare function requestIsHttps(encrypted: boolean, remoteAddress: string | undefined, headers: Record<string, unknown>): boolean;