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 +57 -4
- package/dist/accounts.d.ts +13 -0
- package/dist/accounts.js +42 -1
- package/dist/accounts.js.map +1 -1
- package/dist/auto-reload.d.ts +74 -0
- package/dist/auto-reload.js +65 -0
- package/dist/auto-reload.js.map +1 -0
- package/dist/login-limit.d.ts +48 -0
- package/dist/login-limit.js +90 -0
- package/dist/login-limit.js.map +1 -0
- package/dist/net.d.ts +58 -0
- package/dist/net.js +149 -0
- package/dist/net.js.map +1 -1
- package/dist/oauth-relay.d.ts +15 -5
- package/dist/oauth-relay.js +29 -9
- package/dist/oauth-relay.js.map +1 -1
- package/dist/server.js +200 -34
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +25 -8
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
|
-
|
|
369
|
-
|
|
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 |
|
package/dist/accounts.d.ts
CHANGED
|
@@ -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.
|
package/dist/accounts.js.map
CHANGED
|
@@ -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":"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"}
|
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;
|