dante-watch 0.1.2 → 0.1.4
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 +78 -23
- package/package.json +1 -1
- package/src/bib/answers.mjs +2 -2
- package/src/bib/bib.json +1 -1
- package/src/bib/ear.mjs +24 -21
- package/src/bib/net.json +1 -1
- package/src/bib/net.mjs +7 -9
- package/src/bib/probe.mjs +7 -8
- package/src/bib/pruef.json +1 -0
- package/src/bib/router.mjs +16 -19
- package/src/bib/system.mjs +22 -16
- package/src/bib/systems.json +1 -0
- package/src/bib/wash.mjs +5 -13
- package/src/checks/battery.mjs +15 -10
- package/src/checks/common.mjs +5 -5
- package/src/checks/demo.mjs +2 -2
- package/src/checks/formats.mjs +221 -0
- package/src/checks/hf.mjs +252 -0
- package/src/checks/loc.mjs +2 -4
- package/src/checks/php2shell.mjs +8 -9
- package/src/checks/rechte.mjs +2 -3
- package/src/checks/secrets.mjs +15 -6
- package/src/checks/sshd.mjs +3 -5
- package/src/checks/webshell.mjs +3 -5
- package/src/cli.mjs +15 -10
- package/src/core/check.mjs +4 -8
- package/src/core/consent.mjs +7 -7
- package/src/core/render.mjs +2 -2
- package/src/core/sh.mjs +34 -8
- package/src/i18n-checks.mjs +6 -3
- package/src/i18n.mjs +54 -14
- package/src/mascot.mjs +3 -5
- package/src/me/deep.mjs +37 -0
- package/src/me/diary.mjs +51 -0
- package/src/me/home.mjs +10 -0
- package/src/me/hostkey.mjs +94 -0
- package/src/me/lock.mjs +41 -0
- package/src/me/nudge.mjs +52 -0
- package/src/me/onboard.mjs +102 -0
- package/src/me/overview.mjs +10 -0
- package/src/me/patrol.mjs +43 -0
- package/src/me/pick.mjs +64 -0
- package/src/me/pool.mjs +15 -0
- package/src/me/recon.mjs +124 -0
- package/src/me/refresh.mjs +70 -0
- package/src/me/schedule-deep.mjs +86 -0
- package/src/me/schedule.mjs +120 -0
- package/src/me/servers.mjs +103 -0
- package/src/me/sysid.mjs +113 -0
- package/src/me/sysq.mjs +23 -0
- package/src/me/sysreport.mjs +73 -0
- package/src/me/texts.mjs +412 -0
- package/src/me/user.mjs +70 -0
- package/src/pack/builtin.mjs +115 -4
- package/src/pack/ere.mjs +87 -0
- package/src/pack/install.mjs +6 -8
- package/src/pack/key.mjs +2 -3
- package/src/pack/know.mjs +4 -5
- package/src/pack/pack.mjs +14 -10
- package/src/pack/rules.mjs +109 -1
- package/src/pack/texts.mjs +8 -7
- package/src/session.mjs +321 -51
- package/src/ticker.mjs +11 -10
- package/src/ui/footer.mjs +9 -5
- package/src/ui/job-worker.mjs +4 -4
- package/src/ui/job.mjs +7 -6
- package/src/ui/quips.mjs +1 -2
- package/src/ui/wait.mjs +3 -4
- package/src/version.mjs +11 -0
package/src/bib/router.mjs
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// how many intents share it — the bib decides what is a filler word, not a hand-made list.
|
|
7
|
-
// The answer is honest about doubt: below the threshold, or when most of the words are unknown,
|
|
8
|
-
// it does not guess — it says "unklar" and hands back the two best candidates.
|
|
1
|
+
// Naive Bayes classifier for what the user typed: returns an intent and a probability. No network.
|
|
2
|
+
// Four feature kinds are counted from the example library: first word, words, word pairs, letter
|
|
3
|
+
// triples (so typos like "prüff" or "chek" still land). A feature shared by many intents counts for
|
|
4
|
+
// less, which makes filler words fall out without a stop-word list. Below the confidence threshold it
|
|
5
|
+
// answers "unklar" and returns the two best candidates instead of guessing.
|
|
9
6
|
|
|
10
7
|
const WEIGHT = { f: 1.5, w: 1, b: 1, c: 0.25 };
|
|
11
8
|
const ALPHA = 0.5; // smoothing: an unseen pairing is rare, not impossible
|
|
12
|
-
const SHARP = 2; // measured on the held-out set: 1
|
|
9
|
+
const SHARP = 2; // measured on the held-out set: 1 -> too shy, ≥2.5 -> only bolder, not wiser
|
|
13
10
|
export const SURE = 0.6; // below this the router asks instead of acting
|
|
14
11
|
// Risk-weighted: an intent that only ANSWERS (a question, small talk, a greeting) may speak from
|
|
15
|
-
// SURE_ANSWER on
|
|
12
|
+
// SURE_ANSWER on - a wrong answer is wrong text, never a deed. Actions keep SURE.
|
|
16
13
|
// Measured (25.10.): 135 of 146 question misses had the right intent on top, only under 60 %.
|
|
17
14
|
export const ANSWER_ONLY = new Set(["frage_luecke", "frage_urteil", "frage_gehackt", "frage_dante", "smalltalk", "gruss", "hilfe", "unklar"]);
|
|
18
15
|
export let SURE_ANSWER = Number(process.env.DANTE_SURE_ANSWER || 0.4);
|
|
@@ -48,13 +45,13 @@ export function features(text) {
|
|
|
48
45
|
return out;
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
// The model only keeps raw counts, so it can learn one line at a time (the
|
|
52
|
-
// line the moment it finds a gap and checks again right away). Everything derived
|
|
53
|
-
// filler-word weight, trust
|
|
48
|
+
// The model only keeps raw counts, so it can learn one line at a time (the build server loop adds a
|
|
49
|
+
// line the moment it finds a gap and checks again right away). Everything derived - balance,
|
|
50
|
+
// filler-word weight, trust - is worked out at the moment of hearing, from those counts.
|
|
54
51
|
// balance: every intent weighs the same in total, so one huge intent ("unklar", 10× the others)
|
|
55
52
|
// keeps its breadth of words but stops winning by sheer mass. Measured on the bib, not guessed.
|
|
56
53
|
// trust: a feature seen once ("prüff" in one single line) gets a fifth of its weight, full weight
|
|
57
|
-
// from TRUST sightings on
|
|
54
|
+
// from TRUST sightings on - one example must not turn into "99.9 % sure".
|
|
58
55
|
const TRUST = 5; // measured: 3 still let one "prüff"-line decide alone, 5 does not
|
|
59
56
|
|
|
60
57
|
export function model({ balance = true, trust = TRUST } = {}) {
|
|
@@ -73,7 +70,7 @@ export function learn(m, { intent, text }) {
|
|
|
73
70
|
return m;
|
|
74
71
|
}
|
|
75
72
|
|
|
76
|
-
// The exact inverse of learn
|
|
73
|
+
// The exact inverse of learn - the build server takes a line back out when it proved too broad.
|
|
77
74
|
export function unlearn(m, { intent, text }) {
|
|
78
75
|
const k = m.intents[intent];
|
|
79
76
|
if (!k) return m;
|
|
@@ -112,8 +109,8 @@ export function classify(m, text, { sharp = SHARP, all = false } = {}) {
|
|
|
112
109
|
};
|
|
113
110
|
const words = tokens(text);
|
|
114
111
|
const known = words.length ? words.filter(knownWord).length / words.length : 0;
|
|
115
|
-
// Complement: judge each intent by how badly the line fits
|
|
116
|
-
// (400 lines) then stop swallowing small ones (160 lines)
|
|
112
|
+
// Complement: judge each intent by how badly the line fits all the OTHERS. Big intents
|
|
113
|
+
// (400 lines) then stop swallowing small ones (160 lines) - "ich geh jetzt" stays "raus".
|
|
117
114
|
const restTotal = names.reduce((a, c, i) => a + scale[i] * totals[i], 0);
|
|
118
115
|
const rest = fs.map(([f]) => names.reduce((a, c, i) => a + scale[i] * (m.intents[c].f[f] || 0), 0));
|
|
119
116
|
const raw = names.map((c, i) => {
|
|
@@ -132,11 +129,11 @@ export function classify(m, text, { sharp = SHARP, all = false } = {}) {
|
|
|
132
129
|
return { intent: sure ? best.intent : "unklar", p: best.p, known, ranked: all ? ranked : ranked.slice(0, 3) };
|
|
133
130
|
}
|
|
134
131
|
|
|
135
|
-
// "this machine" in any of the three languages
|
|
132
|
+
// "this machine" in any of the three languages - a slot, not an intent: "check local" is a check
|
|
136
133
|
// whose target is here. A word list decides it, no probability in between.
|
|
137
134
|
const LOCAL = /(^|\s)(lokal|local|localhost|hier|here|aqu[ií]|diese[nm]? (rechner|laptop|mac|pc)|meine?[nm]? (rechner|laptop|mac|pc)|this (machine|computer|box|laptop|mac|pc)|my (own )?(machine|computer|box|laptop|mac|pc)|mi (compu|computadora|pc|equipo|laptop|mac)|este equipo|esta (compu|computadora|pc))(?=$|[\s,.!?])/i;
|
|
138
135
|
|
|
139
|
-
// The value a command needs (target / key path / local), read from the raw line
|
|
136
|
+
// The value a command needs (target / key path / local), read from the raw line - never invented.
|
|
140
137
|
export function slots(text) {
|
|
141
138
|
const ziel = String(text).match(/\b[\w.-]+@[\w.-]+\b/) || String(text).match(/\b\d{1,3}(\.\d{1,3}){3}\b/);
|
|
142
139
|
const pfad = String(text).match(/(?:^|\s)((?:~|\.{0,2})\/\S+)/);
|
package/src/bib/system.mjs
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// S — the moves Dante must RECOGNISE (grows via the same kitchen loop as the language bib)
|
|
5
|
-
// RECIPES — the HANDS: per system family, the exact command and which real line means a hit.
|
|
6
|
-
// There is no E1/E2/E3 depth here: nothing personal to anonymise. The only split is the family,
|
|
7
|
-
// and the family is a SLOT (like ziel/pfad), picked by the fingerprint — not an intent.
|
|
8
|
-
// Dante does not trust what the user says the system is. He reads os-release himself first; that
|
|
9
|
-
// reading is itself a recipe in this book (intent "fingerabdruck").
|
|
1
|
+
// Seeds for the three domain classifiers (system moves, check requests, knowledge questions) and the
|
|
2
|
+
// recipes for system-specific commands. The OS family is read from the target itself
|
|
3
|
+
// (os-release), never taken from what the user says. Unknown families yield "unbekannt", not a verdict.
|
|
10
4
|
|
|
11
|
-
// System families Dante can stand on. Everything else is "unbekannt"
|
|
5
|
+
// System families Dante can stand on. Everything else is "unbekannt" -> Dante says so, never SAFE.
|
|
12
6
|
export const FAMILIES = ["debian", "alpine", "fedora", "arch", "unbekannt"];
|
|
13
|
-
// os-release ID / ID_LIKE
|
|
7
|
+
// os-release ID / ID_LIKE -> family (the fingerprint maps real output to one column).
|
|
14
8
|
export const FAMILY_OF = {
|
|
15
9
|
debian: "debian", ubuntu: "debian", raspbian: "debian", mint: "debian", devuan: "debian",
|
|
16
10
|
alpine: "alpine",
|
|
@@ -20,7 +14,6 @@ export const FAMILY_OF = {
|
|
|
20
14
|
|
|
21
15
|
// Seed phrasings per intent (DE/EN/ES), only to prove the ear. The real bib is cooked by the loop.
|
|
22
16
|
const S = {
|
|
23
|
-
fingerabdruck: ["auf welchem system bin ich", "was läuft hier für ein os", "welche distro", "bin auf debian 11", "ich hab ubuntu", "läuft auf alpine", "das ist ein centos", "which os is this", "im on debian", "running ubuntu 22", "its alpine", "en que sistema estoy", "tengo debian", "es un centos"],
|
|
24
17
|
finde_php: ["läuft hier php", "welche php version", "wo ist mein php", "php 8.1 mit nginx", "ich hab php-fpm", "hab php 7.4 noch", "is php running", "what php version", "php 8.2 fpm", "where is php", "corre php aqui", "que version de php", "tengo php 8.0"],
|
|
25
18
|
pruef_php2shell: ["bin ich von php2shell betroffen", "ist meine php version die lücke", "cve-2026-109618 bei mir", "php 8.1.5 sicher", "ist das die rce lücke", "am i affected by php2shell", "is my php version vulnerable", "php 8.2.3 safe", "estoy afectado por php2shell", "mi php es vulnerable"],
|
|
26
19
|
beleg: ["zeig mir die zeile", "woran siehst du das", "was ist der beweis", "welche zeile beweist das", "show me the line", "whats the proof", "how do you know", "muestrame la linea", "cual es la prueba"],
|
|
@@ -29,8 +22,20 @@ const S = {
|
|
|
29
22
|
export const SYS_PROBE = Object.entries(S).flatMap(([intent, xs]) => xs.map((text) => ({ intent, text })));
|
|
30
23
|
|
|
31
24
|
// The Muster-Bib seed: how a user asks the watchman to look for what is WRONG (beyond php2shell).
|
|
32
|
-
// Recognition only
|
|
25
|
+
// Recognition only - the hands are the deterministic battery in src/checks/. Grown by the loop.
|
|
26
|
+
// lines of the old system-ear intent "fingerabdruck": they now belong to the muster intent meinsystem (same answer)
|
|
27
|
+
const FINGERPRINT_LINES = ["auf welchem system bin ich", "was läuft hier für ein os", "welche distro", "bin auf debian 11", "ich hab ubuntu", "läuft auf alpine", "das ist ein centos", "which os is this", "im on debian", "running ubuntu 22", "its alpine", "en que sistema estoy", "tengo debian", "es un centos"];
|
|
33
28
|
const M = {
|
|
29
|
+
umschauen: ["schau dich um", "lern mich kennen", "sieh dich mal um", "was weißt du über meinen rechner", "mach dich mit meinem system vertraut", "look around", "get to know my machine", "have a look at my setup", "mira a tu alrededor", "conoce mi equipo", "echa un vistazo a mi sistema"],
|
|
30
|
+
scharf: ["schalt dich scharf", "aktiviere die patrouille", "lauf mehrmals am tag", "überwache mich automatisch", "arm yourself", "turn on the patrol", "run on a schedule", "watch my machine automatically", "ponte en marcha", "activa la patrulla", "revisa automáticamente"],
|
|
31
|
+
systeme_info: ["was kannst du mir über meine systeme sagen", "erzähl mir was über meine rechner", "gib mir einen überblick über alles was ich habe", "was weißt du über meine maschinen", "tell me about my systems", "what can you tell me about my machines", "give me an overview of everything i own", "dime algo de mis sistemas", "qué sabes de mis equipos", "dame un resumen de todo lo que tengo"],
|
|
32
|
+
was_los: ["was ist da los", "was geht auf dem server ab", "was läuft gerade auf meinem rechner", "warum ist der so langsam", "wer ist gerade eingeloggt", "welche ports sind offen", "what's going on on my server", "what is running right now", "why is it so slow", "who is logged in", "which ports are open", "qué pasa en mi servidor", "qué está corriendo ahora", "por qué va tan lento", "quién está conectado", "qué puertos están abiertos"],
|
|
33
|
+
meinsystem: [...FINGERPRINT_LINES, "was ist mein system", "welcher ist mein mac", "was für ein rechner ist das", "welches betriebssystem hab ich", "wie viel ram hab ich", "zeig mir die systeminfo", "what machine is this", "which os am i running", "what is my mac", "show system info", "how much memory do i have", "qué sistema tengo", "qué ordenador es este", "cuánta memoria tengo", "info del sistema", "qué versión de linux es"],
|
|
34
|
+
server_finden: ["finde meine server", "such mal meine server", "spür meine rechner auf", "entdecke meine server", "find my servers", "discover my machines", "look for my servers", "search for servers i own", "busca mis servidores", "encuentra mis servidores", "descubre mis máquinas", "encuentra mis servidores por favor"],
|
|
35
|
+
server_status: ["wie geht's meinen servern", "wie läuft es bei meinen servern", "alles ok bei meinen servern", "wie stehen meine server da", "status meiner server", "how are my servers", "how are my servers doing", "is everything ok with my servers", "status of my servers", "cómo están mis servidores", "cómo van mis servidores", "todo bien con mis servidores"],
|
|
36
|
+
server_liste: ["kennst du meine server", "welche server hast du gefunden", "was für server hab ich", "zeig mir meine server", "welche rechner kennst du von mir", "liste meine server auf", "weißt du welche server ich habe", "do you know my servers", "which servers did you find", "what servers do i have", "list my servers", "show me my machines", "qué servidores conoces", "cuáles son mis servidores", "muéstrame mis servidores", "conoces mis servidores"],
|
|
37
|
+
hf: ["prüf meine modelle", "ist das modell sicher zu laden", "schau dir meine ki modelle an", "was darf mein agent", "prüf meine mcp server", "check meine huggingface modelle", "laden meine gewichte fremden code", "check my models", "are my huggingface models safe to load", "look at my mcp servers", "what is my agent allowed to do", "scan my downloaded models", "revisa mis modelos", "son seguros mis modelos de hugging face", "mira mis servidores mcp", "qué puede hacer mi agente"],
|
|
38
|
+
abschalten: ["schalt dich ab", "stopp die patrouille", "lauf nicht mehr automatisch", "nimm den zeitplan raus", "disarm", "turn off the patrol", "stop running automatically", "remove the schedule", "desarmar", "apaga la patrulla", "quita el horario"],
|
|
34
39
|
patrouille: ["prüf alles", "mach die runde", "kompletter check", "check alles durch", "alles scannen", "komplett prüfen", "mach die ganze runde", "scan everything", "full check", "run all checks", "check everything", "revisa todo", "chequeo completo", "escanéalo todo"],
|
|
35
40
|
webshell: ["hat mir wer was reingelegt", "gibt es fremde dateien", "such nach webshells", "ist ne hintertür drin", "schädliche php dateien", "backdoor finden", "fremder code im webroot", "check for webshells", "any backdoor files", "malicious php files", "look for a shell", "busca webshells", "archivos maliciosos", "hay una puerta trasera"],
|
|
36
41
|
secrets: ["ist meine env offen", "leaken meine geheimnisse", "ist mein git public", "sind passwörter sichtbar", "liegt die .env offen", "db passwort sichtbar", "are my secrets exposed", "is my .env public", "exposed env file", "secrets leaking", "mis secretos están expuestos", "está mi env público", "contraseña de la base visible"],
|
|
@@ -39,6 +44,7 @@ const M = {
|
|
|
39
44
|
};
|
|
40
45
|
// The Fachwissen seed: how people ask Dante to explain (what he watches / one topic or finding).
|
|
41
46
|
const W = {
|
|
47
|
+
bericht: ["was ist passiert", "was hast du gemacht", "gibt es was neues", "wie lief die nacht", "hast du was gefunden", "was war seit gestern", "what happened", "what did you do", "anything new", "did you find anything", "what was going on while i was away", "qué pasó", "qué hiciste", "hay novedades", "encontraste algo", "cómo fue la noche"],
|
|
42
48
|
job: ["was überwachst du", "was ist dein job", "was prüfst du alles", "wofür bist du da", "was kannst du inhaltlich", "worauf achtest du", "what do you watch", "what is your job", "what do you check", "what are you for", "what do you look for", "que vigilas", "cual es tu trabajo", "que revisas", "para que sirves", "en que te fijas"],
|
|
43
49
|
thema: ["was ist eine webshell", "woran erkenne ich offene geheimnisse", "warum ist root login gefährlich", "wie prüfst du ssh", "ist das normal", "was tue ich dagegen", "was bedeutet php2shell", "what is a webshell", "what stands out about open secrets", "why is root login dangerous", "how do you check ssh", "is that normal", "what do i do about it", "que es una webshell", "que llama la atencion en los permisos", "por que es peligroso el login de root", "como compruebas ssh", "es normal esto", "que hago al respecto"],
|
|
44
50
|
};
|
|
@@ -46,11 +52,11 @@ export const WISSEN_PROBE = Object.entries(W).flatMap(([intent, xs]) => xs.map((
|
|
|
46
52
|
|
|
47
53
|
export const MUSTER_PROBE = Object.entries(M).flatMap(([intent, xs]) => xs.map((text) => ({ intent, text })));
|
|
48
54
|
|
|
49
|
-
// The
|
|
50
|
-
// the real output. Small and hand-verified
|
|
55
|
+
// The hands. Per family: the exact command Dante runs on the real server, and the rule that reads
|
|
56
|
+
// the real output. Small and hand-verified - this is where "every verdict carries a real line"
|
|
51
57
|
// lives. The loop may PROPOSE additions, but a recipe is only the shape below; the hit-logic is
|
|
52
58
|
// deterministic code in src, never DeepSeek prose. php2shell = CVE-2026-109618 (fictional here):
|
|
53
|
-
// affected PHP < 8.1.27, 8.2.0–8.2.13, 8.3.0–8.3.1
|
|
59
|
+
// affected PHP < 8.1.27, 8.2.0–8.2.13, 8.3.0–8.3.1 - and only when the vulnerable module is loaded.
|
|
54
60
|
export const RECIPES = {
|
|
55
61
|
debian: {
|
|
56
62
|
fingerabdruck: { cmd: ". /etc/os-release 2>/dev/null; echo \"$ID ${VERSION_ID}\"", beleg: "die ID-Zeile aus /etc/os-release" },
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"v":1,"systems":[{"id":"opnsense","kind":"router","name":{"de":"OPNsense","en":"OPNsense","es":"OPNsense"},"identify":[{"probe":"freebsd_version","re":"^[0-9]+\\.[0-9]+-"},{"probe":"uname","re":"^FreeBSD "},{"probe":"opnsense_version","re":"^OPNsense"}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"amazon-linux-2","kind":"server","name":{"de":"Amazon Linux 2","en":"Amazon Linux 2","es":"Amazon Linux 2"},"identify":[{"probe":"os_release","re":"^ID=\"amzn\"$"},{"probe":"os_release","re":"^VERSION_ID=\"2.*\"$"},{"probe":"uname","re":"^Linux.*"}],"facts":{"pkg":"yum","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"freebsd","kind":"server","name":{"de":"FreeBSD","en":"FreeBSD","es":"FreeBSD"},"identify":[{"probe":"freebsd_version","re":"^[0-9]+\\.[0-9]+-"},{"probe":"uname","re":"^FreeBSD "}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf, ipfw","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"pfsense","kind":"router","name":{"de":"pfSense","en":"pfSense","es":"pfSense"},"identify":[{"probe":"platform_file","re":"^pfSense"},{"probe":"uname","re":"^FreeBSD "}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"proxmox-ve","kind":"hypervisor","name":{"de":"Proxmox VE","en":"Proxmox VE","es":"Proxmox VE"},"identify":[{"probe":"os_release","re":"^ID=\"?debian\"?$"},{"probe":"proxmox","re":"^pve-manager/"}],"facts":{"pkg":"apt","init":"systemd","firewall":"pve-firewall (nftables)","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"almalinux","kind":"server","name":{"de":"AlmaLinux","en":"AlmaLinux","es":"AlmaLinux"},"identify":[{"probe":"os_release","re":"^ID=\"almalinux\"$"},{"probe":"redhat_release","re":"^AlmaLinux release .*"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"android","kind":"other","name":{"de":"Android","en":"Android","es":"Android"},"identify":[{"probe":"os_release","re":"^ID=\"?android\"?$"},{"probe":"version_file","re":"^Android version.*$"}],"facts":{}},{"id":"android-tv","kind":"other","name":{"de":"Android TV","en":"Android TV","es":"Android TV"},"identify":[{"probe":"os_release","re":"^ID=\"?android\"?$"},{"probe":"uname","re":"^Linux .* (aarch64|armv7l|armv8l).*$"}],"facts":{}},{"id":"antix","kind":"desktop","name":{"de":"antiX","en":"antiX","es":"antiX"},"identify":[{"probe":"os_release","re":"^ID=\"?antix\"?$"},{"probe":"os_release","re":"^NAME=\"?antiX\"?"}],"facts":{"pkg":"apt","init":"sysvinit","firewall":"iptables"}},{"id":"centos-stream","kind":"server","name":{"de":"CentOS Stream","en":"CentOS Stream","es":"CentOS Stream"},"identify":[{"probe":"os_release","re":"^ID=\"?centos\"?$"},{"probe":"os_release","re":"^NAME=\"?CentOS Stream\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"coreos","kind":"container","name":{"de":"CoreOS Container Linux","en":"CoreOS Container Linux","es":"CoreOS Container Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?coreos\"?$"},{"probe":"version_file","re":"^VERSION=\"?.*\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"dd-wrt","kind":"router","name":{"de":"DD-WRT","en":"DD-WRT","es":"DD-WRT"},"identify":[{"probe":"os_release","re":"^ID=\"dd-wrt\"$"},{"probe":"device_model","re":"^.*$"}],"facts":{"pkg":"opkg","firewall":"iptables"}},{"id":"dragonflybsd","kind":"server","name":{"de":"DragonFly BSD","en":"DragonFly BSD","es":"DragonFly BSD"},"identify":[{"probe":"os_release","re":"^ID=\"dragonfly\"$"},{"probe":"freebsd_version","re":"^.*$"}],"facts":{"pkg":"pkg","init":"rc"}},{"id":"elementary-os","kind":"desktop","name":{"de":"elementary OS","en":"elementary OS","es":"elementary OS"},"identify":[{"probe":"os_release","re":"^ID=\"?elementary\"?$"},{"probe":"os_release","re":"^NAME=\"?elementary OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"hp-ux","kind":"server","name":{"de":"HP-UX","en":"HP-UX","es":"HP-UX"},"identify":[{"probe":"uname","re":"^HP-UX .*"},{"probe":"issue","re":"^HP-UX"}],"facts":{"logs":"/var/adm/syslog/syslog.log"}},{"id":"juniper-junos","kind":"router","name":{"de":"Juniper Junos","en":"Juniper Junos","es":"Juniper Junos"},"identify":[{"probe":"uname","re":"^JUNOS"},{"probe":"uname","re":"JNPR"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"linux-lite","kind":"desktop","name":{"de":"Linux Lite","en":"Linux Lite","es":"Linux Lite"},"identify":[{"probe":"os_release","re":"^ID=\"?linuxlite\"?$"},{"probe":"os_release","re":"^NAME=\"?Linux Lite\"?$"}],"facts":{"pkg":"apt","init":"systemd"}},{"id":"linux-mint","kind":"desktop","name":{"de":"Linux Mint","en":"Linux Mint","es":"Linux Mint"},"identify":[{"probe":"os_release","re":"^ID=\"?linuxmint\"?$"},{"probe":"os_release","re":"^NAME=\"?Linux Mint\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"macos","kind":"desktop","name":{"de":"macOS","en":"macOS","es":"macOS"},"identify":[{"probe":"sw_vers","re":"^ProductName:[[:space:]]*macOS"},{"probe":"uname","re":"^Darwin"}],"facts":{"init":"launchd","sshd":"/etc/ssh/sshd_config"}},{"id":"mx-linux","kind":"desktop","name":{"de":"MX Linux","en":"MX Linux","es":"MX Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?mx\"?$"},{"probe":"os_release","re":"^NAME=\"?MX Linux\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"openbsd","kind":"server","name":{"de":"OpenBSD","en":"OpenBSD","es":"OpenBSD"},"identify":[{"probe":"uname","re":"^OpenBSD .*"},{"probe":"hw_model","re":"^[A-Za-z0-9].*"}],"facts":{"firewall":"pf","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"opensuse-leap","kind":"server","name":{"de":"openSUSE Leap","en":"openSUSE Leap","es":"openSUSE Leap"},"identify":[{"probe":"os_release","re":"^ID=\"opensuse-leap\"$"},{"probe":"os_release","re":"^VERSION_ID=\".*\"$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"opensuse-tumbleweed","kind":"desktop","name":{"de":"openSUSE Tumbleweed","en":"openSUSE Tumbleweed","es":"openSUSE Tumbleweed"},"identify":[{"probe":"os_release","re":"^ID=\"?opensuse-tumbleweed\"?$"},{"probe":"os_release","re":"^NAME=\"?openSUSE Tumbleweed\"?$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","sshd":"/etc/ssh/sshd_config"}},{"id":"pclinuxos","kind":"desktop","name":{"de":"PCLinuxOS","en":"PCLinuxOS","es":"PCLinuxOS"},"identify":[{"probe":"os_release","re":"^ID=\"?pclinuxos\"?$"},{"probe":"os_release","re":"^NAME=\"?PCLinuxOS\"?$"}],"facts":{"init":"systemd","firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"peppermint-os","kind":"desktop","name":{"de":"Peppermint OS","en":"Peppermint OS","es":"Peppermint OS"},"identify":[{"probe":"os_release","re":"^ID=\"?peppermint\"?$"},{"probe":"os_release","re":"^NAME=\"?Peppermint OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"puppy-linux","kind":"desktop","name":{"de":"Puppy Linux","en":"Puppy Linux","es":"Puppy Linux"},"identify":[{"probe":"os_release","re":"^(ID=\"?puppy\"?|NAME=\"?Puppy Linux\"?)$"},{"probe":"version_file","re":"puppy"}],"facts":{}},{"id":"q4os","kind":"desktop","name":{"de":"Q4OS","en":"Q4OS","es":"Q4OS"},"identify":[{"probe":"os_release","re":"^ID=\"?q4os\"?$"},{"probe":"os_release","re":"^NAME=\"?Q4OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"raspberry-pi-os","kind":"embedded","name":{"de":"Raspberry Pi OS","en":"Raspberry Pi OS","es":"Raspberry Pi OS"},"identify":[{"probe":"os_release","re":"^ID=\"?raspbian\"?$"},{"probe":"device_model","re":"^Raspberry Pi"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"rhel","kind":"server","name":{"de":"Red Hat Enterprise Linux","en":"Red Hat Enterprise Linux","es":"Red Hat Enterprise Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?rhel\"?$"},{"probe":"redhat_release","re":"^Red Hat Enterprise Linux"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"rockstor","kind":"nas","name":{"de":"Rockstor","en":"Rockstor","es":"Rockstor"},"identify":[{"probe":"os_release","re":"^ID=\"?rockstor\"?$"},{"probe":"os_release","re":"^NAME=\"?Rockstor\"?$"}],"facts":{"init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"slackware","kind":"desktop","name":{"de":"Slackware Linux","en":"Slackware Linux","es":"Slackware Linux"},"identify":[{"probe":"os_release","re":"^NAME=\"?Slackware\"?$"},{"probe":"version_file","re":"^Slackware [0-9]+\\.[0-9]+"}],"facts":{"firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"solaris","kind":"server","name":{"de":"Oracle Solaris","en":"Oracle Solaris","es":"Oracle Solaris"},"identify":[{"probe":"uname","re":"^SunOS [^ ]+ 5\\.[0-9]+ .*"},{"probe":"issue","re":"^(Oracle )?Solaris"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"sonic","kind":"router","name":{"de":"SONiC","en":"SONiC","es":"SONiC"},"identify":[{"probe":"os_release","re":"^ID=\"?sonic\"?$"},{"probe":"version_file","re":"sonic"}],"facts":{"pkg":"apt","init":"systemd","firewall":"iptables"}},{"id":"tizen","kind":"other","name":{"de":"Tizen","en":"Tizen","es":"Tizen"},"identify":[{"probe":"os_release","re":"^ID=\"?tizen\"?$"},{"probe":"version_file","re":"tizen"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"tomato","kind":"router","name":{"de":"Tomato","en":"Tomato","es":"Tomato"},"identify":[{"probe":"os_release","re":"^ID=\"?tomato\"?$"},{"probe":"issue","re":"tomato"}],"facts":{"firewall":"iptables","logs":"/var/log/messages"}},{"id":"truenas-core","kind":"nas","name":{"de":"TrueNAS CORE","en":"TrueNAS CORE","es":"TrueNAS CORE"},"identify":[{"probe":"version_file","re":"^TrueNAS-.*"},{"probe":"uname","re":"FreeBSD"}],"facts":{"pkg":"pkg","firewall":"pf","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"truenas-scale","kind":"nas","name":{"de":"TrueNAS SCALE","en":"TrueNAS SCALE","es":"TrueNAS SCALE"},"identify":[{"probe":"os_release","re":"^ID=\"truenas\"$"},{"probe":"version_file","re":"^VERSION=\"1\\.2\\.0\"$"}],"facts":{}},{"id":"webos","kind":"other","name":{"de":"webOS","en":"webOS","es":"webOS"},"identify":[{"probe":"os_release","re":"^ID=\"?webos\"?$"},{"probe":"os_release","re":"^NAME=\"?webOS\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"xcp-ng","kind":"hypervisor","name":{"de":"XCP-ng","en":"XCP-ng","es":"XCP-ng"},"identify":[{"probe":"os_release","re":"^ID=\"xcp-ng\"$"},{"probe":"version_file","re":"^XCP-ng version .*$"}],"facts":{"init":"systemd","firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"zorin-os","kind":"desktop","name":{"de":"Zorin OS","en":"Zorin OS","es":"Zorin OS"},"identify":[{"probe":"os_release","re":"^ID=\"?zorin\"?$"},{"probe":"os_release","re":"^NAME=\"?Zorin OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"amazon-linux","kind":"server","name":{"de":"Amazon Linux","en":"Amazon Linux","es":"Amazon Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?amzn\"?$"}],"facts":{"pkg":"dnf, yum","init":"systemd","firewall":"nftables, iptables","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"esxi","kind":"hypervisor","name":{"de":"VMware ESXi","en":"VMware ESXi","es":"VMware ESXi"},"identify":[{"probe":"esxi","re":"^VMware ESXi"}],"facts":{"pkg":"esxcli software","init":"init scripts","firewall":"esxcli network firewall","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"openwrt","kind":"router","name":{"de":"OpenWrt","en":"OpenWrt","es":"OpenWrt"},"identify":[{"probe":"openwrt_release","re":"^DISTRIB_ID='?OpenWrt"}],"facts":{"pkg":"opkg, apk","init":"procd","firewall":"fw4 (nftables)","logs":"logread","sshd":"/etc/config/dropbear"}},{"id":"oracle-linux","kind":"server","name":{"de":"Oracle Linux","en":"Oracle Linux","es":"Oracle Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?ol\"?$"}],"facts":{"pkg":"dnf, yum","init":"systemd","firewall":"firewalld","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"rocky-linux","kind":"server","name":{"de":"Rocky Linux","en":"Rocky Linux","es":"Rocky Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?rocky\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"synology-dsm","kind":"nas","name":{"de":"Synology DSM","en":"Synology DSM","es":"Synology DSM"},"identify":[{"probe":"synology","re":"^productversion=\"?[0-9]"}],"facts":{"pkg":"Paketzentrum (synopkg)","init":"systemd","firewall":"DSM-Firewall (iptables)","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"alpine","kind":"server","name":{"de":"Alpine Linux","en":"Alpine Linux","es":"Alpine Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?alpine\"?$"}],"facts":{"pkg":"apk","init":"OpenRC"}},{"id":"arch-linux","kind":"server","name":{"de":"Arch Linux","en":"Arch Linux","es":"Arch Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?arch\"?$"}],"facts":{"pkg":"pacman","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"arista-eos","kind":"router","name":{"de":"Arista EOS","en":"Arista EOS","es":"Arista EOS"},"identify":[{"probe":"os_release","re":"^ID=\"?eos\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"artix-linux","kind":"desktop","name":{"de":"Artix Linux","en":"Artix Linux","es":"Artix Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?artix\"?$"}],"facts":{"pkg":"pacman","init":"openrc"}},{"id":"balenaos","kind":"embedded","name":{"de":"balenaOS","en":"balenaOS","es":"balenaOS"},"identify":[{"probe":"os_release","re":"^ID=\"?balena\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"bottlerocket","kind":"container","name":{"de":"Bottlerocket","en":"Bottlerocket","es":"Bottlerocket"},"identify":[{"probe":"os_release","re":"^ID=\"?bottlerocket\"?$"}],"facts":{"init":"systemd"}},{"id":"centos","kind":"server","name":{"de":"CentOS","en":"CentOS","es":"CentOS"},"identify":[{"probe":"os_release","re":"^ID=\"?centos\"?$"}],"facts":{"init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"chromeos","kind":"desktop","name":{"de":"ChromeOS","en":"ChromeOS","es":"ChromeOS"},"identify":[{"probe":"os_release","re":"^ID=\"?chromeos\"?$"}],"facts":{}},{"id":"cisco-ios","kind":"router","name":{"de":"Cisco IOS","en":"Cisco IOS","es":"Cisco IOS"},"identify":[{"probe":"os_release","re":"^ID=\"?cisco-ios\"?$"}],"facts":{}},{"id":"clearos","kind":"server","name":{"de":"ClearOS","en":"ClearOS","es":"ClearOS"},"identify":[{"probe":"os_release","re":"^ID=\"?clearos\"?$"}],"facts":{"pkg":"yum","init":"systemd","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"debian","kind":"server","name":{"de":"Debian GNU/Linux","en":"Debian GNU/Linux","es":"Debian GNU/Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?debian\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"deepin","kind":"desktop","name":{"de":"deepin","en":"deepin","es":"deepin"},"identify":[{"probe":"os_release","re":"^ID=\"?deepin\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"dietpi","kind":"embedded","name":{"de":"DietPi","en":"DietPi","es":"DietPi"},"identify":[{"probe":"os_release","re":"^ID=\"?dietpi\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"fedora","kind":"desktop","name":{"de":"Fedora","en":"Fedora","es":"Fedora"},"identify":[{"probe":"os_release","re":"^ID=\"?fedora\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","sshd":"/etc/ssh/sshd_config"}},{"id":"flatcar","kind":"container","name":{"de":"Flatcar Container Linux","en":"Flatcar Container Linux","es":"Flatcar Container Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?flatcar\"?$"}],"facts":{"init":"systemd"}},{"id":"freenas","kind":"nas","name":{"de":"FreeNAS","en":"FreeNAS","es":"FreeNAS"},"identify":[{"probe":"os_release","re":"^ID=\"freebsd\"$"}],"facts":{}},{"id":"garuda-linux","kind":"desktop","name":{"de":"Garuda Linux","en":"Garuda Linux","es":"Garuda Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?garuda\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"google-container-optimized-os","kind":"server","name":{"de":"Google Container-Optimized OS","en":"Google Container-Optimized OS","es":"Google Container-Optimized OS"},"identify":[{"probe":"os_release","re":"^ID=\"?cos\"?$"}],"facts":{"init":"systemd"}},{"id":"illumos","kind":"server","name":{"de":"illumos","en":"illumos","es":"illumos"},"identify":[{"probe":"uname","re":"^SunOS .* (illumos|oi|omnios|openindiana).*"}],"facts":{"init":"smf","sshd":"/etc/ssh/sshd_config"}},{"id":"kali-linux","kind":"server","name":{"de":"Kali Linux","en":"Kali Linux","es":"Kali Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?kali\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"manjaro","kind":"desktop","name":{"de":"Manjaro Linux","en":"Manjaro Linux","es":"Manjaro Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?manjaro\"?$"}],"facts":{"pkg":"pacman","init":"systemd"}},{"id":"mikrotik-routeros","kind":"router","name":{"de":"MikroTik RouterOS","en":"MikroTik RouterOS","es":"MikroTik RouterOS"},"identify":[{"probe":"os_release","re":"^ID=\"routeros\"$"}],"facts":{}},{"id":"minix","kind":"other","name":{"de":"MINIX 3","en":"MINIX 3","es":"MINIX 3"},"identify":[{"probe":"uname","re":"^.*MINIX.*$"}],"facts":{}},{"id":"netbsd","kind":"server","name":{"de":"NetBSD","en":"NetBSD","es":"NetBSD"},"identify":[{"probe":"uname","re":"^NetBSD "}],"facts":{"init":"rc.d","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"openfiler","kind":"nas","name":{"de":"Openfiler","en":"Openfiler","es":"Openfiler"},"identify":[{"probe":"os_release","re":"^ID=\"openfiler\"$"}],"facts":{"firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"pop-os","kind":"desktop","name":{"de":"Pop!_OS","en":"Pop!_OS","es":"Pop!_OS"},"identify":[{"probe":"os_release","re":"^ID=\"?pop\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"qnap-qts","kind":"nas","name":{"de":"QNAP QTS","en":"QNAP QTS","es":"QNAP QTS"},"identify":[{"probe":"platform_file","re":"^TS-\\S+|^NAS\\b|QNAP"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"rancher-os","kind":"container","name":{"de":"RancherOS","en":"RancherOS","es":"RancherOS"},"identify":[{"probe":"os_release","re":"^ID=\"?rancheros\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"solus","kind":"desktop","name":{"de":"Solus","en":"Solus","es":"Solus"},"identify":[{"probe":"os_release","re":"^ID=\"?solus\"?$"}],"facts":{"pkg":"eopkg","init":"systemd"}},{"id":"suse-linux-enterprise-server","kind":"server","name":{"de":"SUSE Linux Enterprise Server","en":"SUSE Linux Enterprise Server","es":"SUSE Linux Enterprise Server"},"identify":[{"probe":"os_release","re":"^ID=\"?sles\"?$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"tails","kind":"desktop","name":{"de":"Tails","en":"Tails","es":"Tails"},"identify":[{"probe":"os_release","re":"^ID=\"?tails\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"talos-linux","kind":"container","name":{"de":"Talos Linux","en":"Talos Linux","es":"Talos Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?talos\"?$"}],"facts":{}},{"id":"truenas","kind":"nas","name":{"de":"TrueNAS","en":"TrueNAS","es":"TrueNAS"},"identify":[{"probe":"os_release","re":"^ID=\"?truenas\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"ubuntu","kind":"server","name":{"de":"Ubuntu","en":"Ubuntu","es":"Ubuntu"},"identify":[{"probe":"os_release","re":"^ID=\"?ubuntu\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"ubuntu-core","kind":"embedded","name":{"de":"Ubuntu Core","en":"Ubuntu Core","es":"Ubuntu Core"},"identify":[{"probe":"os_release","re":"^ID=\"?ubuntu-core\"?$"}],"facts":{"pkg":"snap","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"void-linux","kind":"desktop","name":{"de":"Void Linux","en":"Void Linux","es":"Void Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?void\"?$"}],"facts":{"pkg":"xbps","init":"runit","sshd":"/etc/ssh/sshd_config"}},{"id":"vyos","kind":"router","name":{"de":"VyOS","en":"VyOS","es":"VyOS"},"identify":[{"probe":"os_release","re":"^ID=\"?vyos\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"windows-server","kind":"server","name":{"de":"Windows Server","en":"Windows Server","es":"Windows Server"},"identify":[{"probe":"windows_ver","re":"^Microsoft Windows \\[Version [0-9.]+\\]$"}],"facts":{}},{"id":"yocto","kind":"embedded","name":{"de":"Yocto","en":"Yocto","es":"Yocto"},"identify":[{"probe":"os_release","re":"^ID=\"?yocto\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}}]}
|
package/src/bib/wash.mjs
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// Limits (on purpose "better too little than too much"):
|
|
8
|
-
// - {NAME} only fires for (a) a known first name + capitalized surname, (b) a title cue
|
|
9
|
-
// (Herr/Frau/Dr./Mr./Sr./...) + capitalized name, (c) an intro cue ("mein Name ist", "me llamo",
|
|
10
|
-
// "my name is") + name, (d) Spanish messaging cue ("escribirle a danny jose ...", lowercase ok). Lone first names, lowercase names and unknown pairs stay untouched.
|
|
11
|
-
// - Windows paths with spaces are cut at the first space. Relative paths (src/x.mjs) stay.
|
|
12
|
-
// - Domains are only recognised with a known TLD (so index.php / app.js survive).
|
|
13
|
-
// - {NUM} also eats plain big numbers (1000000); versions (8.3.6) and CVE-2026-109618 stay.
|
|
1
|
+
// Replaces personal values in a sentence (paths, hosts, mails, tokens, numbers, names) with placeholders
|
|
2
|
+
// before it is used as training data. wash(text) returns { text, hits }.
|
|
3
|
+
// The order of the rules matters, longer patterns first. It prefers leaving something in over
|
|
4
|
+
// removing too much: names are only replaced with a clear cue (known first name + surname, title,
|
|
5
|
+
// "my name is"), domains need a known TLD, versions and CVE ids stay.
|
|
14
6
|
|
|
15
7
|
const L = "\\p{L}\\p{N}_";
|
|
16
8
|
const TLD = "com|net|org|io|de|es|fr|uk|us|ai|app|dev|co|info|biz|eu|online|space|xyz|site|cloud|me|tv|ch|at|nl|it|ru|cn|jp|do|edu|gov|store|shop|pro|tech";
|
package/src/checks/battery.mjs
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// stays plain code.
|
|
1
|
+
// Assembles the checks from rules. Built-in rules are the free tier; each installed pack adds rules or
|
|
2
|
+
// replaces one with the same id (newest wins). Deep rules (secret formats, models, agent config) are
|
|
3
|
+
// kept out of the light battery and run in the deep run or on request. `rechte` has no rule type
|
|
4
|
+
// yet and stays plain code.
|
|
6
5
|
import { versionCheck } from "./php2shell.mjs";
|
|
7
6
|
import { exposedCheck } from "./secrets.mjs";
|
|
8
7
|
import { patternCheck } from "./webshell.mjs";
|
|
9
8
|
import { sshdCheck } from "./sshd.mjs";
|
|
9
|
+
import { formatsCheck } from "./formats.mjs";
|
|
10
|
+
import { modelCardCheck, modelFilesCheck, agentConfigCheck } from "./hf.mjs";
|
|
10
11
|
import { rechte } from "./rechte.mjs";
|
|
11
12
|
import { BUILTIN } from "../pack/builtin.mjs";
|
|
12
13
|
import { loadPacks } from "../pack/pack.mjs";
|
|
13
14
|
|
|
14
|
-
const FACTORY = { version_cve: versionCheck, path_exposed: exposedCheck, file_pattern: patternCheck, sshd_setting: sshdCheck };
|
|
15
|
+
const FACTORY = { version_cve: versionCheck, path_exposed: exposedCheck, file_pattern: patternCheck, sshd_setting: sshdCheck, secret_format: formatsCheck, model_card: modelCardCheck, model_files: modelFilesCheck, agent_config: agentConfigCheck };
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
// Deep rules (the Prüf-Bib's secret formats) are not part of the light battery that the patrol and the session run;
|
|
18
|
+
// they run in the deep run only (buildDeep).
|
|
19
|
+
export const buildBattery = (rules) => [...rules.filter((r) => !r.deep).map((r) => FACTORY[r.type](r)), rechte];
|
|
20
|
+
export const buildDeep = (rules) => rules.filter((r) => r.deep).map((r) => FACTORY[r.type](r));
|
|
17
21
|
|
|
18
22
|
// a rule of a later list replaces the rule with the same id, new ids are added
|
|
19
23
|
export function mergeRules(base, ...more) {
|
|
@@ -30,15 +34,16 @@ export const BATTERY = buildBattery(BUILTIN.rules);
|
|
|
30
34
|
// checks. notices lists the pack files he refused (code per file), for the person to be told once.
|
|
31
35
|
export function activeBattery(opts) {
|
|
32
36
|
const { packs, notices } = loadPacks(opts);
|
|
33
|
-
|
|
37
|
+
const rules = rulesWith(packs);
|
|
38
|
+
return { battery: buildBattery(rules), deep: buildDeep(rules), packs, notices };
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
// muster intent
|
|
41
|
+
// muster intent -> check id. The ear recognises the worry; this says which hand to use.
|
|
37
42
|
export const MUSTER = { pruef_php2shell: "php2shell", secrets: "secrets", webshell: "webshell", sshd: "sshd", rechte: "rechte" };
|
|
38
43
|
|
|
39
44
|
export const checkById = (id, list = BATTERY) => list.find((c) => c.id === id) || null;
|
|
40
45
|
|
|
41
|
-
// Run one check safely
|
|
46
|
+
// Run one check safely - a thrown check becomes an honest UNKNOWN, never a crash or a false verdict.
|
|
42
47
|
export function runCheck(check) {
|
|
43
48
|
try { return check.run(); }
|
|
44
49
|
catch (e) { return { id: check.id, title: check.title, verdict: "unknown", was: "Check brach ab.", wie: String(e.message || e), wo: "", evidence: [] }; }
|
package/src/checks/common.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Helpers shared by the checks: quoting, web root lookup, line trimming. Read-only.
|
|
2
2
|
import { run, firstLine } from "../core/sh.mjs";
|
|
3
3
|
|
|
4
4
|
// Single-quote an argument for the remote shell. Double quotes would let the shell expand a `$` in
|
|
5
|
-
// a regex (e.g. $_GET
|
|
5
|
+
// a regex (e.g. $_GET -> the _ variable), which silently mangled the webshell pattern. Single quotes
|
|
6
6
|
// make every character literal; an embedded ' is closed, escaped and reopened.
|
|
7
7
|
export const sq = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
|
8
8
|
|
|
@@ -13,17 +13,17 @@ export const WEBROOTS = ["/var/www/html", "/var/www", "/usr/share/nginx/html", "
|
|
|
13
13
|
// Which of the standard web roots actually exist on the target (its own output decides).
|
|
14
14
|
// Exit code is unreliable here: the for-loop's last `[ -d ] && echo` fails for the last missing
|
|
15
15
|
// path, so the loop exits non-zero even when it printed real roots. We trust the OUTPUT (the lines
|
|
16
|
-
// the machine actually printed), not the exit code
|
|
16
|
+
// the machine actually printed), not the exit code - ran is enough.
|
|
17
17
|
export function webRoots() {
|
|
18
18
|
const r = run("for d in " + WEBROOTS.join(" ") + "; do [ -d \"$d\" ] && echo \"$d\"; done");
|
|
19
19
|
let roots = r.ran ? r.out.split("\n").map((s) => s.trim()).filter(Boolean) : [];
|
|
20
|
-
// Drop a root that sits inside another found root (/var/www/html under /var/www)
|
|
20
|
+
// Drop a root that sits inside another found root (/var/www/html under /var/www) - otherwise a
|
|
21
21
|
// deep search finds the same file through both and reports it twice.
|
|
22
22
|
roots = roots.filter((d) => !roots.some((o) => o !== d && (d === o || d.startsWith(o + "/"))));
|
|
23
23
|
return { ran: r.ran, roots, line: firstLine(r.err || r.out) };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// First N non-empty lines of some output, trimmed
|
|
26
|
+
// First N non-empty lines of some output, trimmed - for a compact, honest evidence list.
|
|
27
27
|
export function lines(s, n = 10) {
|
|
28
28
|
return String(s || "").split("\n").map((x) => x.trim()).filter(Boolean).slice(0, n);
|
|
29
29
|
}
|
package/src/checks/demo.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Harmless demo check for --demo: a temp file stands in for an open door, so the whole
|
|
2
|
+
// ask -> plan -> confirm -> fix -> verify loop can be tried without touching anything real.
|
|
3
3
|
import { run, firstLine } from "../core/sh.mjs";
|
|
4
4
|
import { result, evidence, SAFE, RISK } from "../core/check.mjs";
|
|
5
5
|
|