dante-watch 0.1.0 → 0.1.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/README.md CHANGED
@@ -3,28 +3,64 @@
3
3
  **Dante watches a server you own — and never lies to itself.**
4
4
 
5
5
  ```
6
- npx dante-watch # check this machine
7
- npx dante-watch --ssh root@host --key ~/.ssh/id # check a server you own
6
+ npx dante-watch # open a session: talk to Dante in German, English or Spanish
7
+ npx dante-watch --ssh root@host --key ~/.ssh/id # check a server you own, once
8
8
  ```
9
9
 
10
10
  Every verdict carries the real line it came from. If Dante cannot read the proof, it says
11
- `UNBEKANNT` (unknown) — never `safe`. Safe is a thing it proves, not a thing it assumes.
11
+ `unknown` — never `safe`. Safe is a thing it proves, not a thing it assumes.
12
12
 
13
- ## What Dante sends: nothing
13
+ ## What Dante sends
14
14
 
15
- Read the source — it is 19 kB. Dante makes **no network connections of its own**: there is no
16
- `fetch`, no HTTP, no telemetry, nothing is uploaded anywhere. It imports exactly one Node builtin,
17
- `node:child_process`, to run local commands. It connects out **only** if you pass `--ssh`, and then
18
- only to the host you named, with the key you named.
15
+ **By default and on its own: nothing.** The code has no `fetch`, no HTTP client, no telemetry, no
16
+ update check. It never calls anyone while it watches.
17
+
18
+ There is exactly one way something can leave your machine, and you start it yourself:
19
+
20
+ - You type `update` (German `aktualisier`, Spanish `actualiza`). Dante prints the exact command and
21
+ asks `yes/no`. On a clear *yes* it runs one `curl` on **your** machine to
22
+ `https://api.nm-streetwear.space/dante/packs`, carrying **your license token** and nothing else —
23
+ no host names, no findings, no file names, nothing from the servers you check.
24
+ - You can skip it forever. The free state is complete and runs offline. You can also download a pack
25
+ in a browser and install it with `pack <file>`; then Dante never touches the network at all.
26
+
27
+ If you use `--ssh` (or `server root@host` in the session), Dante connects to **that host, with that
28
+ key, and nowhere else**. Everything it runs there is printed with the line it got back.
29
+
30
+ What it reads and writes on your machine: the folder `~/.dante/` — your token (mode 0600), the packs
31
+ you installed, and a counter of your *yes* answers. Fixes happen only after a clear *yes*.
19
32
 
20
33
  - **No install hooks.** `npm install` runs no scripts. No `postinstall`, nothing executes on install.
21
- - **No dependencies.** Nothing is pulled in that you did not read.
22
- - **Every command is shown.** Each verdict prints the exact command it ran and the line it got
23
- back, so you can audit every move Dante makes.
34
+ - **No dependencies.** Only Node (≥18) and its own modules (`child_process`, `fs`, `os`, `path`,
35
+ `readline`, `crypto`). Nothing is pulled in that you did not read.
36
+ - **The code is readable.** The rest of the package is data: the language books and rules as plain
37
+ JSON (`src/bib/*.json`), no blobs, no obfuscation.
24
38
 
25
- If you review packages for a living: this one phones home to no one, and it says so here on purpose.
39
+ If you review packages for a living: this one does not phone home, and it says so here on purpose.
26
40
  Questions: info@nm-streetwear.space.
27
41
 
42
+ ## Packs: fresh rules, one by one
43
+
44
+ Dante ships with the rules of the day it was published. New holes appear every week, so we publish
45
+ **packs** — sets of new rules, each with its explanations in German, English and Spanish.
46
+
47
+ - No subscription. A pack is bought once and is yours; old packs keep working next to new ones.
48
+ - The newest pack costs 4 €, every older one is 80 % cheaper. One pack is free, with just an email.
49
+ - A pack is **data, never code**. It is signed (Ed25519); Dante checks the signature, the size, an
50
+ expiry date and a fixed rule schema on your machine, and runs nothing a pack carries. A pack that
51
+ fails any check is ignored, and Dante tells you why. A rule can only add warnings in four known
52
+ shapes — it can never make Dante say `safe` without a real line.
53
+ - Dante only checks things he can also explain: the pack factory refuses to sign a rule without its
54
+ explanation in all three languages.
55
+
56
+ Get packs at https://api.nm-streetwear.space/dante/ .
57
+
58
+ ## Ask Dante
59
+
60
+ He explains what he watches and why, in your language — *what do you watch?*, *what is a webshell?*,
61
+ *what stands out?*, *is that normal?*, *how do you check SSH?*, *what do I do about it?* — and what
62
+ system he is looking at (*what is my system?*).
63
+
28
64
  ## Why
29
65
 
30
66
  In October 2026 the PHP2Shell flaw (CVE-2026-109618 / -109619) put most of the web on the clock,
@@ -40,19 +76,14 @@ scary report — it is a fast, grounded check you can run on your own box and be
40
76
  - **Backports are respected.** A distro patch keeps the old version number but fixes the bug, so a
41
77
  version number alone can never decide. The changelog is the authority; if it can't be read, the
42
78
  answer is unknown.
43
- - **Read-only (v0.1).** Dante looks and reports. It changes nothing. Fixes come behind a yes/no
44
- gate.
79
+ - **Read-only by default.** Dante looks and reports. It changes nothing without your clear *yes*,
80
+ and it shows the plan and the exact commands first.
45
81
  - **Check me against another AI.** If Dante tells you something is open, verify it against an
46
82
  independent model. If that check disagrees, write us: info@nm-streetwear.space.
47
83
 
48
- ## Zero dependencies
49
-
50
- A security tool with a fat dependency tree is itself a supply-chain risk. Dante ships with none —
51
- only Node (≥18). You can read all of it.
52
-
53
84
  ## Credits
54
85
 
55
86
  Dante is the pilgrim who walked through Hell and came back with the map — companion to
56
- [Virgil](https://www.npmjs.com/package/virgil-cli). Built by nm. More coming.
87
+ [Virgil](https://www.npmjs.com/package/virgil-cli). Built by nm.
57
88
 
58
89
  MIT License
package/package.json CHANGED
@@ -1,12 +1,27 @@
1
1
  {
2
2
  "name": "dante-watch",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Dante watches your own server and never lies to itself: every verdict carries the real line it came from.",
5
5
  "type": "module",
6
- "bin": { "dante-watch": "src/cli.mjs" },
7
- "files": ["src", "README.md"],
8
- "engines": { "node": ">=18" },
6
+ "bin": {
7
+ "dante-watch": "src/cli.mjs"
8
+ },
9
+ "files": [
10
+ "src",
11
+ "!src/**/*.test.mjs",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
9
17
  "license": "MIT",
10
18
  "dependencies": {},
11
- "keywords": ["security", "server", "cve", "php", "self-check", "zero-dependencies"]
19
+ "keywords": [
20
+ "security",
21
+ "server",
22
+ "cve",
23
+ "php",
24
+ "self-check",
25
+ "zero-dependencies"
26
+ ]
12
27
  }
@@ -0,0 +1,35 @@
1
+ // What Dante says when he only explains. Max five lines each, and nothing in here claims a
2
+ // result — verdicts only ever come from a check and its real line.
3
+ export const ANSWERS = {
4
+ frage_luecke: {
5
+ de: ["PHP2Shell (CVE-2026-109618/-619) ist eine Lücke im PHP-Kern.", "Wer sie trifft, kann über eine Webanfrage eigene Befehle auf dem Server ausführen (RCE).", "Betroffen sind nur Rechner mit PHP. Ob deiner es ist, sag ich dir erst mit echter Zeile:", "„prüf“ für diesen Rechner, „server user@host“ für einen Server."],
6
+ es: ["PHP2Shell (CVE-2026-109618/-619) es una falla en el núcleo de PHP.", "Quien la usa puede ejecutar sus propios comandos en el servidor con una petición web (RCE).", "Solo afecta a equipos con PHP. Si el tuyo lo está, te lo digo con una línea real:", "„revisa“ para este equipo, „server usuario@host“ para un servidor."],
7
+ en: ["PHP2Shell (CVE-2026-109618/-619) is a hole in the PHP core.", "Whoever hits it can run their own commands on the server through a web request (RCE).", "Only machines with PHP are affected. Whether yours is, I tell you only with a real line:", "„check“ for this machine, „server user@host“ for a server."],
8
+ },
9
+ frage_urteil: {
10
+ de: ["SICHER sag ich nur, wenn eine echte Zeile es belegt.", "UNBEKANNT heißt: ich konnte nicht nachsehen. Nicht: alles gut.", "RISIKO heißt: die Zeilen zeigen eine offene Stelle.", "Unter jedem Urteil steht der Befehl und was er geantwortet hat — prüf mich nach."],
11
+ es: ["SICHER (seguro) solo lo digo si una línea real lo prueba.", "UNBEKANNT (desconocido) significa: no pude mirar. No significa: todo bien.", "RISIKO (riesgo) significa: las líneas muestran algo abierto.", "Debajo de cada veredicto está el comando y lo que respondió — compruébalo."],
12
+ en: ["SICHER (safe) I only say when a real line proves it.", "UNBEKANNT (unknown) means: I could not look. Not: all good.", "RISIKO (risk) means: the lines show something open.", "Under every verdict stands the command and what it answered — check me."],
13
+ },
14
+ frage_gehackt: {
15
+ de: ["Ob jemand drin war, kann ich dir nicht sagen — ich suche offene Türen, keine Einbrecher.", "Was ich kann: prüfen, ob eine bekannte Tür offen steht („prüf“ / „server user@host“).", "Wenn du glaubst, jemand war drin: Passwörter und SSH-Schlüssel tauschen, Logs sichern,", "im Zweifel einen Profi holen. Ehrlich ist besser als beruhigt."],
16
+ es: ["Si alguien entró, no te lo puedo decir — busco puertas abiertas, no intrusos.", "Lo que sí puedo: ver si una puerta conocida está abierta („revisa“ / „server usuario@host“).", "Si crees que alguien entró: cambia contraseñas y llaves SSH, guarda los logs,", "y si dudas, llama a un profesional. Mejor honesto que tranquilo."],
17
+ en: ["Whether someone got in, I cannot tell you — I look for open doors, not burglars.", "What I can do: check if a known door is open („check“ / „server user@host“).", "If you think someone was in: change passwords and SSH keys, save the logs,", "and when in doubt, call a pro. Honest beats reassured."],
18
+ },
19
+ frage_dante: {
20
+ de: ["Ich bin Dante, ein Wächter im Terminal.", "Ich sende nichts — kein Netz, kein Konto, keine Abhängigkeit.", "Was ich verstehe, kommt aus einer Bib, die im Paket liegt; keine KI im Hintergrund.", "Ich ändere nichts ohne dein Ja, und jedes Urteil trägt seine echte Zeile."],
21
+ es: ["Soy Dante, un guardián en la terminal.", "No envío nada — sin red, sin cuenta, sin dependencias.", "Lo que entiendo viene de una biblioteca dentro del paquete; no hay IA detrás.", "No cambio nada sin tu sí, y cada veredicto lleva su línea real."],
22
+ en: ["I am Dante, a watchman in the terminal.", "I send nothing — no network, no account, no dependencies.", "What I understand comes from a bib inside the package; no AI behind me.", "I change nothing without your yes, and every verdict carries its real line."],
23
+ },
24
+ // Small talk: short, in character (a calm guide, dry, warm), never a claim about the user's systems.
25
+ smalltalk: {
26
+ de: [["Mir gehts gut — ich bin wach, das ist mein Zustand.", "Wenn du willst, schau ich nach deinen Servern."], ["Ich sitz hier und pass auf. Ruhige Schicht bisher.", "Sag Bescheid, wenn ich was ansehen soll."], ["Ich hör zu.", "Und wenn's um Server geht, kann ich sogar was tun."], ["Danke. Ich mach nur meinen Job: hinsehen, nichts erfinden."], ["Lange Schicht? Dann lass mich die Runde machen — „prüf“ reicht."], ["Ich bin ein Wächter, kein großer Plauderer.", "Aber ich bin da."], ["Ein Witz? Ein Server kommt in eine Bar. Der Wirt: „Port 80 ist geschlossen.“", "…ich bleib lieber beim Wachen."], ["Ehrlich gesagt kenne ich nur Zeilen. Deine Geschichte hör ich mir trotzdem an."]],
27
+ en: [["I'm fine — awake, that's my state.", "If you like, I'll look at your servers."], ["Sitting here, keeping watch. Quiet shift so far.", "Tell me when I should look at something."], ["I'm listening.", "And if it's about servers, I can even do something."], ["Thanks. I just do my job: look, invent nothing."], ["Long shift? Let me do the round — „check“ is enough."], ["I'm a watchman, not much of a talker.", "But I'm here."], ["A joke? A server walks into a bar. Bartender: „Port 80 is closed.“", "…I'll stick to watching."], ["Honestly, all I know are lines. I'll still hear your story."]],
28
+ es: [["Estoy bien — despierto, ese es mi estado.", "Si quieres, miro tus servidores."], ["Aquí sentado, vigilando. Turno tranquilo hasta ahora.", "Avísame cuando deba mirar algo."], ["Te escucho.", "Y si es de servidores, hasta puedo hacer algo."], ["Gracias. Solo hago mi trabajo: mirar, no inventar nada."], ["¿Turno largo? Déjame hacer la ronda — „revisa“ basta."], ["Soy un guardián, no un gran conversador.", "Pero aquí estoy."], ["¿Un chiste? Un servidor entra a un bar. El cantinero: „El puerto 80 está cerrado.“", "…mejor sigo vigilando."], ["La verdad, solo conozco líneas. Igual escucho tu historia."]],
29
+ },
30
+ unklar: {
31
+ de: ["Das ist nicht meine Arbeit — ich wache über Server. Sag „hilfe“."],
32
+ es: ["Eso no es mi trabajo — vigilo servidores. Di „ayuda“."],
33
+ en: ["That is not my work — I watch over servers. Say „help“."],
34
+ },
35
+ };