alvin-bot 4.12.0 → 4.12.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/CHANGELOG.md +124 -0
- package/README.md +186 -21
- package/dist/handlers/commands.js +6 -0
- package/dist/handlers/message.js +54 -15
- package/dist/handlers/stuck-timer.js +54 -0
- package/dist/index.js +75 -3
- package/dist/providers/claude-sdk-provider.js +29 -1
- package/dist/services/allowed-users-gate.js +56 -0
- package/dist/services/cron.js +17 -0
- package/dist/services/exec-guard.js +26 -1
- package/dist/services/fallback-order.js +4 -1
- package/dist/services/file-permissions.js +93 -0
- package/dist/services/personality.js +55 -30
- package/dist/services/session-persistence.js +14 -2
- package/dist/services/subagents.js +23 -5
- package/dist/services/timing-safe-bearer.js +51 -0
- package/dist/web/doctor-api.js +8 -2
- package/dist/web/server.js +7 -3
- package/dist/web/setup-api.js +5 -2
- package/docs/security.md +279 -0
- package/package.json +4 -1
- package/skills/social-fetch/SKILL.md +385 -0
- package/skills/webcheck/SKILL.md +150 -0
- package/test/allowed-users-gate.test.ts +98 -0
- package/test/claude-sdk-tool-use-id.test.ts +180 -0
- package/test/exec-guard-metachars.test.ts +110 -0
- package/test/file-permissions.test.ts +130 -0
- package/test/stuck-timer.test.ts +116 -0
- package/test/subagent-toolset-allowlist.test.ts +146 -0
- package/test/subagents-toolset.test.ts +22 -2
- package/test/sync-task-timeout.test.ts +153 -0
- package/test/system-prompt-background-hint.test.ts +17 -0
- package/test/timing-safe-bearer.test.ts +65 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: social-fetch
|
|
3
|
+
description: Use when the user shares an Instagram, TikTok, YouTube, or Twitter/X URL and wants the content analyzed, fact-checked, and optionally saved. Also use when user says "check this", "was sagst du dazu", "schau dir das an", "analyze this post", "is this legit", or pastes a social media link without further instruction.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Bash
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
12
|
+
- Agent
|
|
13
|
+
- WebSearch
|
|
14
|
+
- WebFetch
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Social Media Fetch & Intelligence
|
|
18
|
+
|
|
19
|
+
Analysiert Social-Media-Content ganzheitlich: Download, Transkription, Bildanalyse, Faktencheck, Safety-Check, Nutzwert-Bewertung.
|
|
20
|
+
|
|
21
|
+
## URL-Erkennung
|
|
22
|
+
|
|
23
|
+
Trigger bei URLs von:
|
|
24
|
+
- **Instagram:** `instagram.com/p/`, `instagram.com/reel/`, `instagram.com/stories/`
|
|
25
|
+
- **TikTok:** `tiktok.com/@`, `vm.tiktok.com/`
|
|
26
|
+
- **YouTube:** `youtube.com/watch`, `youtu.be/`, `youtube.com/shorts/`
|
|
27
|
+
- **Twitter/X:** `twitter.com/`, `x.com/`
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
```dot
|
|
32
|
+
digraph social_fetch {
|
|
33
|
+
rankdir=TB;
|
|
34
|
+
node [shape=box];
|
|
35
|
+
|
|
36
|
+
"URL erhalten" -> "1. Metadata extrahieren";
|
|
37
|
+
"1. Metadata extrahieren" -> "2. Content-Typ erkennen";
|
|
38
|
+
"2. Content-Typ erkennen" -> "3a. Video/Audio transkribieren" [label="Video/Reel"];
|
|
39
|
+
"2. Content-Typ erkennen" -> "3b. Bilder analysieren" [label="Bild/Carousel"];
|
|
40
|
+
"2. Content-Typ erkennen" -> "3a+3b" [label="Kombi"];
|
|
41
|
+
"3a. Video/Audio transkribieren" -> "4. Faktencheck";
|
|
42
|
+
"3b. Bilder analysieren" -> "4. Faktencheck";
|
|
43
|
+
"3a+3b" -> "4. Faktencheck";
|
|
44
|
+
"4. Faktencheck" -> "5. Tech/Safety Check" [label="Tech-Content?"];
|
|
45
|
+
"4. Faktencheck" -> "6. Nutzwert-Bewertung" [label="Sonstiges"];
|
|
46
|
+
"5. Tech/Safety Check" -> "6. Nutzwert-Bewertung";
|
|
47
|
+
"6. Nutzwert-Bewertung" -> "7. Report an User";
|
|
48
|
+
"7. Report an User" -> "8. Download-Frage";
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Phase 1: Metadata extrahieren
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Universell via yt-dlp (funktioniert fuer YT, TikTok, IG, Twitter)
|
|
56
|
+
yt-dlp --dump-json --no-download "<URL>" > /tmp/social-meta.json
|
|
57
|
+
|
|
58
|
+
# Relevante Felder extrahieren
|
|
59
|
+
python3 -c "
|
|
60
|
+
import json
|
|
61
|
+
d = json.load(open('/tmp/social-meta.json'))
|
|
62
|
+
print(f'Title: {d.get(\"title\", \"?\")}' )
|
|
63
|
+
print(f'Uploader: {d.get(\"uploader\", d.get(\"channel\", \"?\"))}' )
|
|
64
|
+
print(f'Platform: {d.get(\"extractor_key\", \"?\")}' )
|
|
65
|
+
print(f'Duration: {d.get(\"duration\", 0)}s' )
|
|
66
|
+
print(f'Views: {d.get(\"view_count\", \"?\")}' )
|
|
67
|
+
print(f'Likes: {d.get(\"like_count\", \"?\")}' )
|
|
68
|
+
print(f'Upload date: {d.get(\"upload_date\", \"?\")}' )
|
|
69
|
+
print(f'Description: {d.get(\"description\", \"\")[:500]}' )
|
|
70
|
+
print(f'Thumbnails: {len(d.get(\"thumbnails\", []))}' )
|
|
71
|
+
print(f'Formats: {len(d.get(\"formats\", []))}' )
|
|
72
|
+
# Detect content type
|
|
73
|
+
has_video = d.get('duration', 0) > 0
|
|
74
|
+
has_images = 'carousel' in str(d).lower() or d.get('_type') == 'playlist'
|
|
75
|
+
print(f'Has video: {has_video}')
|
|
76
|
+
print(f'Has images: {has_images}')
|
|
77
|
+
"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Wenn yt-dlp fehlschlaegt** (private IG Posts etc.):
|
|
81
|
+
1. Tier 2 CDP Browser: `~/.claude/hub/SCRIPTS/browser.sh cdp goto <url>` + Screenshot
|
|
82
|
+
2. Cookies exportieren fuer yt-dlp: `--cookies /tmp/ig-cookies.txt`
|
|
83
|
+
3. Oder `instaloader` fuer Instagram: `python3 -m instaloader -- -<shortcode>`
|
|
84
|
+
|
|
85
|
+
## Phase 2: Content-Typ erkennen
|
|
86
|
+
|
|
87
|
+
| Signal | Typ | Naechster Schritt |
|
|
88
|
+
|--------|-----|-------------------|
|
|
89
|
+
| `duration > 0` | Video/Reel/Clip | Transkription + Bildanalyse (Thumbnails/Frames) |
|
|
90
|
+
| Carousel/Multi-Image | Bilderkarussell | Alle Bilder analysieren |
|
|
91
|
+
| Einzelbild, duration=0 | Statisches Bild | Bildanalyse |
|
|
92
|
+
| duration > 0 + Carousel | Kombi | Beides |
|
|
93
|
+
|
|
94
|
+
## Phase 3a: Video/Audio transkribieren
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 1. Audio extrahieren
|
|
98
|
+
yt-dlp -x --audio-format mp3 -o "/tmp/social-audio.%(ext)s" "<URL>"
|
|
99
|
+
|
|
100
|
+
# 2. Transkription via Groq Whisper (schnell + kostenlos)
|
|
101
|
+
curl -s https://api.groq.com/openai/v1/audio/transcriptions \
|
|
102
|
+
-H "Authorization: Bearer $GROQ_API_KEY" \
|
|
103
|
+
-F "file=@/tmp/social-audio.mp3" \
|
|
104
|
+
-F "model=whisper-large-v3-turbo" \
|
|
105
|
+
-F "response_format=text" > /tmp/social-transcript.txt
|
|
106
|
+
|
|
107
|
+
# 3. Falls >25MB: Erst komprimieren
|
|
108
|
+
ffmpeg -i /tmp/social-audio.mp3 -b:a 64k -ar 16000 /tmp/social-audio-small.mp3
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Sprache:** Auto-Detect (kein `language` Parameter). Ergebnis in Originalsprache.
|
|
112
|
+
|
|
113
|
+
## Phase 3b: Bilder analysieren
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Thumbnail/Frame als Bild speichern
|
|
117
|
+
yt-dlp --write-thumbnail --skip-download -o "/tmp/social-thumb" "<URL>"
|
|
118
|
+
|
|
119
|
+
# Oder: Keyframes aus Video extrahieren (1 Frame pro 10s)
|
|
120
|
+
ffmpeg -i /tmp/social-video.mp4 -vf "fps=1/10" /tmp/social-frame-%03d.jpg
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Bildanalyse** via Read-Tool (multimodal):
|
|
124
|
+
- Text im Bild lesen (OCR-artig)
|
|
125
|
+
- UI-Screenshots interpretieren
|
|
126
|
+
- Diagramme/Charts verstehen
|
|
127
|
+
- Code-Snippets erkennen
|
|
128
|
+
- Personen/Kontext beschreiben
|
|
129
|
+
|
|
130
|
+
## Phase 4: Faktencheck
|
|
131
|
+
|
|
132
|
+
### Allgemeiner Faktencheck
|
|
133
|
+
Fuer JEDEN Post durchfuehren:
|
|
134
|
+
|
|
135
|
+
1. **Behauptungen extrahieren** — Was wird konkret behauptet? (Zahlen, Statistiken, Zitate, Fakten)
|
|
136
|
+
2. **Quellen pruefen** — WebSearch nach jeder zentralen Behauptung
|
|
137
|
+
3. **Bias erkennen** — Wer postet? Welches Interesse? Affiliate-Links? Sponsored?
|
|
138
|
+
4. **Aktualitaet** — Stimmen die Infos noch? Veraltet?
|
|
139
|
+
5. **Kontext** — Fehlt Kontext der die Aussage relativiert?
|
|
140
|
+
|
|
141
|
+
### Bewertungsskala
|
|
142
|
+
|
|
143
|
+
| Emoji | Bewertung | Bedeutung |
|
|
144
|
+
|-------|-----------|-----------|
|
|
145
|
+
| :check: | Verifiziert | Fakten geprueft und korrekt |
|
|
146
|
+
| :warning: | Teilweise | Kern stimmt, aber Nuancen fehlen oder uebertrieben |
|
|
147
|
+
| :x: | Falsch/Irrefuehrend | Zentrale Behauptungen widerlegt |
|
|
148
|
+
| :question: | Nicht verifizierbar | Keine zuverlaessigen Quellen gefunden |
|
|
149
|
+
|
|
150
|
+
## Phase 5: Tech/Safety Check (nur bei Tech-Content)
|
|
151
|
+
|
|
152
|
+
Wenn der Post ein **Tool, Library, GitHub-Repo, SaaS, API** bewirbt:
|
|
153
|
+
|
|
154
|
+
### Repository finden
|
|
155
|
+
```bash
|
|
156
|
+
# GitHub-Suche
|
|
157
|
+
gh search repos "<tool-name>" --sort=stars --limit=5
|
|
158
|
+
# Oder direkt wenn URL im Post
|
|
159
|
+
gh repo view <owner/repo> --json name,description,stargazersCount,forkCount,updatedAt,license,openIssues
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Safety-Checklist (Repo-Level)
|
|
163
|
+
|
|
164
|
+
| Check | Command | Red Flag |
|
|
165
|
+
|-------|---------|----------|
|
|
166
|
+
| Stars/Forks | `gh repo view --json stargazersCount` | <100 Stars bei "populaerem" Tool |
|
|
167
|
+
| Letzter Commit | `gh repo view --json updatedAt` | >6 Monate her |
|
|
168
|
+
| Lizenz | `gh repo view --json license` | Keine Lizenz / proprietaer |
|
|
169
|
+
| Issues | `gh repo view --json openIssues` | Viele offene Security-Issues |
|
|
170
|
+
| Dependencies | `gh api repos/{owner}/{repo}/dependency-graph/sbom` | Bekannte CVEs |
|
|
171
|
+
| README | Content pruefen | Kein README, kein Docs |
|
|
172
|
+
| Maintainer | `gh api users/{owner}` | Neuer Account, keine Historie |
|
|
173
|
+
| Funding/Sponsor | Check README/FUNDING.yml | Crypto/Scam-Signale |
|
|
174
|
+
|
|
175
|
+
### Code Security Audit (PFLICHT bei Tools die man installieren/ausfuehren wuerde)
|
|
176
|
+
|
|
177
|
+
**Ziel:** Sicherstellen dass kein Schadcode, keine versteckten Backdoors, keine Datenexfiltration.
|
|
178
|
+
|
|
179
|
+
#### Quick Scan (immer durchfuehren)
|
|
180
|
+
```bash
|
|
181
|
+
# 1. Repo klonen in temp
|
|
182
|
+
REPO_DIR=$(mktemp -d)
|
|
183
|
+
git clone --depth=1 <repo-url> "$REPO_DIR"
|
|
184
|
+
|
|
185
|
+
# 2. Verdaechtige Patterns suchen
|
|
186
|
+
grep -rn --include="*.{js,ts,py,sh,go,rs}" \
|
|
187
|
+
-E "(eval\(|exec\(|child_process|subprocess|os\.system|fetch\(|XMLHttpRequest|curl |wget |nc |reverse.shell|bind.shell)" \
|
|
188
|
+
"$REPO_DIR" | head -30
|
|
189
|
+
|
|
190
|
+
# 3. Hardcoded Secrets/IPs/Domains suchen
|
|
191
|
+
grep -rn --include="*.{js,ts,py,json,yml,yaml,toml}" \
|
|
192
|
+
-E "([0-9]{1,3}\.){3}[0-9]{1,3}|https?://[a-z0-9]+([\-\.][a-z0-9]+)*\.[a-z]{2,}" \
|
|
193
|
+
"$REPO_DIR" | grep -v "node_modules\|\.git\|localhost\|127\.0\.0\.1\|example\.com\|github\.com\|npmjs\|pypi" | head -20
|
|
194
|
+
|
|
195
|
+
# 4. Obfuscated Code erkennen
|
|
196
|
+
grep -rn --include="*.{js,ts}" \
|
|
197
|
+
-E "(atob\(|btoa\(|Buffer\.from\(.*base64|\\\\x[0-9a-f]{2}|\\\\u[0-9a-f]{4}|fromCharCode)" \
|
|
198
|
+
"$REPO_DIR" | head -10
|
|
199
|
+
|
|
200
|
+
# 5. Netzwerk-Calls in unerwarteten Stellen
|
|
201
|
+
grep -rn --include="*.{js,ts,py}" \
|
|
202
|
+
-E "(\.send\(|\.post\(|requests\.(get|post)|urllib|aiohttp|axios\.(get|post)|fetch\()" \
|
|
203
|
+
"$REPO_DIR" | grep -v "test\|spec\|__test__\|mock" | head -20
|
|
204
|
+
|
|
205
|
+
# 6. Aufraumen
|
|
206
|
+
rm -rf "$REPO_DIR"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### Deep Scan (bei verdaechtigen Findings oder bei Tools die Systemzugriff brauchen)
|
|
210
|
+
```bash
|
|
211
|
+
# Package-Manager Checks
|
|
212
|
+
# NPM: postinstall Scripts sind ein beliebter Angriffsvektor
|
|
213
|
+
cat "$REPO_DIR/package.json" | python3 -c "
|
|
214
|
+
import json, sys
|
|
215
|
+
pkg = json.load(sys.stdin)
|
|
216
|
+
scripts = pkg.get('scripts', {})
|
|
217
|
+
for key in ['preinstall', 'postinstall', 'prepare', 'prepublish']:
|
|
218
|
+
if key in scripts:
|
|
219
|
+
print(f'⚠️ {key}: {scripts[key]}')
|
|
220
|
+
deps = {**pkg.get('dependencies', {}), **pkg.get('devDependencies', {})}
|
|
221
|
+
print(f'Dependencies: {len(deps)}')
|
|
222
|
+
"
|
|
223
|
+
|
|
224
|
+
# Python: setup.py kann beliebigen Code ausfuehren
|
|
225
|
+
grep -n "os\.\|subprocess\.\|exec\|eval\|import.*requests" "$REPO_DIR/setup.py" 2>/dev/null
|
|
226
|
+
|
|
227
|
+
# Docker: Was wird im Container ausgefuehrt?
|
|
228
|
+
grep -n "RUN\|CMD\|ENTRYPOINT\|EXPOSE\|ENV" "$REPO_DIR/Dockerfile" 2>/dev/null | head -15
|
|
229
|
+
|
|
230
|
+
# GitHub Actions: Workflow-Injection?
|
|
231
|
+
grep -rn "run:\|uses:" "$REPO_DIR/.github/workflows/" 2>/dev/null | head -20
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### Red Flags Matrix
|
|
235
|
+
|
|
236
|
+
| Severity | Signal | Bedeutung |
|
|
237
|
+
|----------|--------|-----------|
|
|
238
|
+
| **KRITISCH** | `eval()` mit User-Input / Netzwerk-Daten | Remote Code Execution moeglich |
|
|
239
|
+
| **KRITISCH** | Obfuscated Code (base64-encoded Scripts) | Versteckter Payload |
|
|
240
|
+
| **KRITISCH** | Outbound HTTP in postinstall | Datenexfiltration bei Installation |
|
|
241
|
+
| **KRITISCH** | Hardcoded IPs/Domains (nicht Docs/Tests) | C2 Server / Exfiltration |
|
|
242
|
+
| **HOCH** | Uebermässige Permissions (root, sudo, alle Env-Vars) | Privilege Escalation |
|
|
243
|
+
| **HOCH** | Liest ~/.ssh, ~/.aws, ~/.config, Keychain | Credential Theft |
|
|
244
|
+
| **HOCH** | Schreibt in /etc, /usr, ~/.bashrc, ~/.zshrc | Persistence / Manipulation |
|
|
245
|
+
| **MITTEL** | Viele Dependencies mit wenig Stars | Supply Chain Risk |
|
|
246
|
+
| **MITTEL** | Minified Source ohne Build-Pipeline | Schwer zu auditieren |
|
|
247
|
+
| **NIEDRIG** | Kein SECURITY.md / keine CVE Policy | Unreifes Projekt |
|
|
248
|
+
|
|
249
|
+
#### Empfehlung formulieren
|
|
250
|
+
|
|
251
|
+
Nach dem Security-Check IMMER eine klare Empfehlung:
|
|
252
|
+
|
|
253
|
+
- **SAFE** — Code sauber, bekannte Maintainer, transparente Dependencies
|
|
254
|
+
- **CAUTION** — Einige Findings, aber erklaerbar (z.B. eval in Template-Engine). Nur in Sandbox nutzen.
|
|
255
|
+
- **AVOID** — Verdaechtige Patterns, nicht vertrauenswuerdig. Nicht installieren.
|
|
256
|
+
- **MALWARE** — Eindeutig schaedlicher Code. Nicht anfassen. Ggf. GitHub Report.
|
|
257
|
+
|
|
258
|
+
### SaaS/Closed-Source Tools
|
|
259
|
+
- **Pricing transparent?** Oder Bait-and-Switch?
|
|
260
|
+
- **Datenschutz:** Wo werden Daten gespeichert? DSGVO?
|
|
261
|
+
- **Alternativen:** Gibt es Open-Source-Alternativen?
|
|
262
|
+
- **Track Record:** Wie lange existiert das Unternehmen?
|
|
263
|
+
- **Permissions:** Was will die App/Extension fuer Rechte? Proportional zum Nutzen?
|
|
264
|
+
|
|
265
|
+
## Phase 6: Nutzwert-Bewertung
|
|
266
|
+
|
|
267
|
+
### Fuer Ali/Alev-B bewerten
|
|
268
|
+
|
|
269
|
+
| Dimension | Fragen |
|
|
270
|
+
|-----------|--------|
|
|
271
|
+
| **Relevanz** | Passt es zu IT-Delivery, Consulting, SaaS, DevOps, AI? |
|
|
272
|
+
| **Einsatz** | Koennen wir es direkt nutzen? In einem Projekt? Als Content-Inspiration? |
|
|
273
|
+
| **ROI** | Lohnt sich der Zeitaufwand? Kostenlos vs. Paid? |
|
|
274
|
+
| **Qualitaet** | Ist der Content gut gemacht? Substanz oder Hype? |
|
|
275
|
+
| **Sharing** | Lohnt es sich, den Content weiterzuteilen oder darauf zu reagieren? |
|
|
276
|
+
|
|
277
|
+
### Bewertungs-Rating
|
|
278
|
+
|
|
279
|
+
- **S-Tier:** Sofort einsetzen / Must-have Tool
|
|
280
|
+
- **A-Tier:** Sehr nuetzlich, bei Gelegenheit einbauen
|
|
281
|
+
- **B-Tier:** Interessant, merken fuer spaeter
|
|
282
|
+
- **C-Tier:** Nett zu wissen, kein Handlungsbedarf
|
|
283
|
+
- **F-Tier:** Muell / Scam / Zeitverschwendung
|
|
284
|
+
|
|
285
|
+
## Phase 7: Report
|
|
286
|
+
|
|
287
|
+
Dem User IMMER einen strukturierten Report liefern:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
## [Platform-Emoji] [Titel/Thema]
|
|
291
|
+
|
|
292
|
+
**Creator:** @username (X Follower, Y Posts)
|
|
293
|
+
**Typ:** Video/Reel/Carousel (Xs / N Bilder)
|
|
294
|
+
**Datum:** TT.MM.JJJJ
|
|
295
|
+
|
|
296
|
+
### Inhalt
|
|
297
|
+
[Zusammenfassung in 3-5 Saetzen]
|
|
298
|
+
|
|
299
|
+
### Transkript (Kurzfassung)
|
|
300
|
+
[Wichtigste Aussagen, bei Video]
|
|
301
|
+
|
|
302
|
+
### Faktencheck [Emoji]
|
|
303
|
+
- Behauptung 1: [Status + Quelle]
|
|
304
|
+
- Behauptung 2: [Status + Quelle]
|
|
305
|
+
|
|
306
|
+
### Tech-Check (falls zutreffend)
|
|
307
|
+
- Repo: [Link] | Stars | Lizenz | Letzter Commit
|
|
308
|
+
- Safety: [OK/Warnung/Kritisch]
|
|
309
|
+
- Alternativen: [Falls vorhanden]
|
|
310
|
+
|
|
311
|
+
### Nutzwert [Rating]
|
|
312
|
+
[1-2 Saetze warum nuetzlich/nicht]
|
|
313
|
+
|
|
314
|
+
### Empfehlung
|
|
315
|
+
[Konkreter Vorschlag: nutzen/merken/ignorieren]
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Phase 8: Download-Frage
|
|
319
|
+
|
|
320
|
+
**IMMER am Ende fragen:**
|
|
321
|
+
|
|
322
|
+
> Soll ich die Assets (Video/Bilder) nach `~/Desktop/SocialMedia-Fetch/[ordner-name]/` downloaden?
|
|
323
|
+
|
|
324
|
+
Erst bei Bestaetigung:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Ordner anlegen
|
|
328
|
+
FOLDER=~/Desktop/SocialMedia-Fetch/<kurzer-name>
|
|
329
|
+
mkdir -p "$FOLDER"
|
|
330
|
+
|
|
331
|
+
# Video (beste Qualitaet)
|
|
332
|
+
yt-dlp -o "$FOLDER/video.%(ext)s" "<URL>"
|
|
333
|
+
|
|
334
|
+
# Thumbnail
|
|
335
|
+
yt-dlp --write-thumbnail --skip-download -o "$FOLDER/thumb" "<URL>"
|
|
336
|
+
|
|
337
|
+
# Beschreibung + Metadaten
|
|
338
|
+
yt-dlp --dump-json --no-download "<URL>" | python3 -c "
|
|
339
|
+
import json, sys
|
|
340
|
+
d = json.load(sys.stdin)
|
|
341
|
+
with open('$FOLDER/info.md', 'w') as f:
|
|
342
|
+
f.write(f'# {d.get(\"title\", \"?\")}\n\n')
|
|
343
|
+
f.write(f'**URL:** {d.get(\"webpage_url\", \"?\")}\n')
|
|
344
|
+
f.write(f'**Creator:** {d.get(\"uploader\", \"?\")}\n')
|
|
345
|
+
f.write(f'**Datum:** {d.get(\"upload_date\", \"?\")}\n')
|
|
346
|
+
f.write(f'**Views:** {d.get(\"view_count\", \"?\")}\n\n')
|
|
347
|
+
f.write(f'## Beschreibung\n\n{d.get(\"description\", \"\")}\n')
|
|
348
|
+
"
|
|
349
|
+
|
|
350
|
+
# Transkript speichern (falls vorhanden)
|
|
351
|
+
cp /tmp/social-transcript.txt "$FOLDER/transcript.txt" 2>/dev/null
|
|
352
|
+
|
|
353
|
+
# Faktencheck-Report
|
|
354
|
+
# (wird vom Agent aus Phase 7 Report generiert und als report.md gespeichert)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Ordner-Benennung
|
|
358
|
+
|
|
359
|
+
Format: `YYYY-MM-DD_platform_kurzname`
|
|
360
|
+
|
|
361
|
+
Beispiele:
|
|
362
|
+
- `2026-04-13_youtube_cursor-ai-review`
|
|
363
|
+
- `2026-04-13_instagram_devops-metrics-carousel`
|
|
364
|
+
- `2026-04-13_tiktok_claude-code-hack`
|
|
365
|
+
|
|
366
|
+
Max 50 Zeichen, lowercase, Bindestriche, keine Sonderzeichen.
|
|
367
|
+
|
|
368
|
+
## Eskalation bei Problemen
|
|
369
|
+
|
|
370
|
+
| Problem | Loesung |
|
|
371
|
+
|---------|---------|
|
|
372
|
+
| yt-dlp 403/Login required | Tier 2 CDP Cookies exportieren |
|
|
373
|
+
| Instagram private Post | `instaloader --login=<user>` oder CDP |
|
|
374
|
+
| TikTok Geo-Block | VPN-Hinweis an User |
|
|
375
|
+
| Video >25MB fuer Whisper | ffmpeg Kompression auf 64kbps |
|
|
376
|
+
| Kein Audio (Slideshow) | Nur Bildanalyse, Captions lesen |
|
|
377
|
+
| Rate Limited | Pause + Retry mit Backoff |
|
|
378
|
+
|
|
379
|
+
## Erweiterungen (nach Ermessen)
|
|
380
|
+
|
|
381
|
+
- **Hashtag-Analyse:** Welche Hashtags? Trending? Nische?
|
|
382
|
+
- **Engagement-Metriken:** Like/View Ratio als Qualitaetssignal
|
|
383
|
+
- **Creator-Profil:** Schneller Check wer der Creator ist (Expertise, Follower, Posting-Frequenz)
|
|
384
|
+
- **Vergleichbare Posts:** Gibt es bessere/ausfuehrlichere Quellen zum gleichen Thema?
|
|
385
|
+
- **Content-Inspiration:** Falls relevant fuer Alev-B Social — als Inspiration vormerken?
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: webcheck
|
|
3
|
+
description: Use when the user wants a security/SEO audit of a website, says "webcheck", "check die seite", "security audit", "site audit", "pruef mal", or provides a domain/URL to analyze. Runs DNS, SSL, headers, performance, tech stack, data leaks, and SEO checks via CLI tools.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Grep
|
|
10
|
+
- Agent
|
|
11
|
+
- WebSearch
|
|
12
|
+
- WebFetch
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# WebCheck — Website Security & SEO Audit
|
|
16
|
+
|
|
17
|
+
Fuehrt einen umfassenden WebCheck-Style Audit durch — komplett via CLI, kein externer Service noetig.
|
|
18
|
+
|
|
19
|
+
## Trigger
|
|
20
|
+
|
|
21
|
+
- "webcheck fuer X", "check mal X", "security audit X", "wie steht X da"
|
|
22
|
+
- Jede Domain/URL die der User zur Analyse gibt
|
|
23
|
+
|
|
24
|
+
## Audit-Checks (alle via Bash)
|
|
25
|
+
|
|
26
|
+
### 1. DNS Records
|
|
27
|
+
```bash
|
|
28
|
+
DOMAIN="example.com"
|
|
29
|
+
dig +short $DOMAIN A && dig +short $DOMAIN AAAA && dig +short $DOMAIN MX
|
|
30
|
+
dig +short $DOMAIN NS && dig +short $DOMAIN TXT && dig +short $DOMAIN CAA
|
|
31
|
+
dig +short www.$DOMAIN CNAME
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. SSL/TLS
|
|
35
|
+
```bash
|
|
36
|
+
echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | \
|
|
37
|
+
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. HTTP Headers + Security Headers (7-Check)
|
|
41
|
+
```bash
|
|
42
|
+
curl -sI https://$DOMAIN | grep -iE "strict-transport|content-security|x-frame|x-content-type|x-xss|referrer-policy|permissions-policy|x-powered-by|server:"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Pruefen: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy, HSTS, Permissions-Policy, CSP
|
|
46
|
+
|
|
47
|
+
### 4. Performance
|
|
48
|
+
```bash
|
|
49
|
+
curl -s -o /dev/null -w "TTFB: %{time_starttransfer}s | Total: %{time_total}s | Size: %{size_download}B | HTTP: %{http_code}" https://$DOMAIN
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 5. IP + Geolocation
|
|
53
|
+
```bash
|
|
54
|
+
IP=$(dig +short $DOMAIN A | head -1)
|
|
55
|
+
curl -s "https://ipapi.co/$IP/json/" | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{d.get(\"city\")}, {d.get(\"country_name\")} | {d.get(\"org\")}')"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 6. robots.txt + Sitemap
|
|
59
|
+
```bash
|
|
60
|
+
curl -s https://$DOMAIN/robots.txt | head -20
|
|
61
|
+
curl -s https://$DOMAIN/sitemap.xml | head -20
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 7. Tech Stack (HTML Source Analysis)
|
|
65
|
+
```bash
|
|
66
|
+
curl -s https://$DOMAIN | python3 -c "
|
|
67
|
+
import sys; html = sys.stdin.read().lower()
|
|
68
|
+
techs = {'React':'react' in html, 'Next.js':'__next' in html or '_next' in html,
|
|
69
|
+
'Vite':'vite' in html, 'Tailwind':'tailwind' in html,
|
|
70
|
+
'Stripe':'stripe' in html, 'WordPress':'wp-content' in html,
|
|
71
|
+
'Umami':'umami' in html or 'analytics.alev' in html,
|
|
72
|
+
'GA4':'gtag' in html or 'googletagmanager' in html}
|
|
73
|
+
for k,v in techs.items():
|
|
74
|
+
if v: print(f' ✅ {k}')
|
|
75
|
+
"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 8. Domain WHOIS
|
|
79
|
+
```bash
|
|
80
|
+
whois $DOMAIN | grep -iE "registrar|creation|expiry|updated|status" | head -10
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 9. Redirect Chain
|
|
84
|
+
```bash
|
|
85
|
+
curl -sIL https://www.$DOMAIN | grep -E "^HTTP|^location|^Location"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 10. Data Leaks + Security
|
|
89
|
+
```bash
|
|
90
|
+
# Secrets in HTML
|
|
91
|
+
curl -s https://$DOMAIN | grep -oiE "(api[_-]?key|secret|token|password)[[:space:]]*[:=][[:space:]]*['\"][^'\"]{8,}" | head -5
|
|
92
|
+
# Mixed Content
|
|
93
|
+
curl -s https://$DOMAIN | grep -c "http://"
|
|
94
|
+
# SRI
|
|
95
|
+
curl -s https://$DOMAIN | grep -c "integrity="
|
|
96
|
+
# Cookies
|
|
97
|
+
curl -sI https://$DOMAIN | grep -i "set-cookie"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Report Format
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
## 🔍 $DOMAIN — WebCheck Report
|
|
104
|
+
|
|
105
|
+
### Server & Netzwerk
|
|
106
|
+
| Check | Ergebnis | Status |
|
|
107
|
+
[IP, Server, HTTP/2, TTFB, Size, Redirects]
|
|
108
|
+
|
|
109
|
+
### SSL/TLS
|
|
110
|
+
[Issuer, Valid until, SAN, HSTS, Mixed Content]
|
|
111
|
+
|
|
112
|
+
### Security Headers — X/7
|
|
113
|
+
[Table mit allen 7 Headers]
|
|
114
|
+
|
|
115
|
+
### DNS
|
|
116
|
+
[Alle Records + CAA/DNSSEC Status]
|
|
117
|
+
|
|
118
|
+
### Tech Stack
|
|
119
|
+
[Erkannte Technologien]
|
|
120
|
+
|
|
121
|
+
### SEO & Crawlability
|
|
122
|
+
[robots.txt, sitemap, meta tags, schema, leaks, SRI]
|
|
123
|
+
|
|
124
|
+
### Domain
|
|
125
|
+
[Registrar, created, expires, auto-renewal]
|
|
126
|
+
|
|
127
|
+
### Score: XX/100
|
|
128
|
+
[Zusammenfassung + Quick Wins]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Scoring
|
|
132
|
+
|
|
133
|
+
| Bereich | Max Punkte |
|
|
134
|
+
|---------|-----------|
|
|
135
|
+
| Security Headers (7/7) | 25 |
|
|
136
|
+
| SSL/TLS + HSTS | 15 |
|
|
137
|
+
| DNS (CAA, SPF, DKIM, DMARC) | 15 |
|
|
138
|
+
| Performance (TTFB <200ms) | 10 |
|
|
139
|
+
| SEO (robots, sitemap, schema, meta) | 15 |
|
|
140
|
+
| No Data Leaks | 10 |
|
|
141
|
+
| Tech/Config (HTTP/2, redirects) | 10 |
|
|
142
|
+
|
|
143
|
+
## Quick Fixes
|
|
144
|
+
|
|
145
|
+
Nach dem Audit immer konkrete Empfehlungen mit Prioritaet:
|
|
146
|
+
- 🔴 HOCH — Security-relevant, sofort fixen
|
|
147
|
+
- 🟡 MITTEL — SEO/Best-Practice, bei Gelegenheit
|
|
148
|
+
- 🟢 NIEDRIG — Nice-to-have
|
|
149
|
+
|
|
150
|
+
Falls Hostinger hPanel noetig (CAA, DKIM, DMARC): CDP Chrome nutzen falls Session aktiv, sonst User fragen.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v4.12.2 — ALLOWED_USERS startup hard-fail gate.
|
|
3
|
+
*
|
|
4
|
+
* When the Telegram bot token is configured but ALLOWED_USERS is empty,
|
|
5
|
+
* starting the bot would leave it open to any Telegram user sending a DM.
|
|
6
|
+
* Previously this only emitted a console.warn and the bot started anyway.
|
|
7
|
+
*
|
|
8
|
+
* v4.12.2 introduces a pure gate function that decides whether to refuse
|
|
9
|
+
* startup, with two explicit escape hatches:
|
|
10
|
+
* 1. AUTH_MODE=open — user explicitly wants an open bot
|
|
11
|
+
* 2. ALVIN_INSECURE_ACKNOWLEDGED=1 — explicit opt-out for test/scripted envs
|
|
12
|
+
*
|
|
13
|
+
* This test file exercises the pure gate. The actual wiring in src/index.ts
|
|
14
|
+
* is a thin if-block that calls process.exit(1) on deny.
|
|
15
|
+
*/
|
|
16
|
+
import { describe, it, expect } from "vitest";
|
|
17
|
+
import { checkAllowedUsersGate } from "../src/services/allowed-users-gate.js";
|
|
18
|
+
|
|
19
|
+
describe("allowed-users-gate (v4.12.2)", () => {
|
|
20
|
+
it("allows startup when ALLOWED_USERS is populated", () => {
|
|
21
|
+
const result = checkAllowedUsersGate({
|
|
22
|
+
hasTelegram: true,
|
|
23
|
+
allowedUsersCount: 1,
|
|
24
|
+
authMode: "allowlist",
|
|
25
|
+
insecureAcknowledged: false,
|
|
26
|
+
});
|
|
27
|
+
expect(result.allowed).toBe(true);
|
|
28
|
+
expect(result.reason).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("BLOCKS startup when telegram enabled but allowedUsers empty (allowlist mode)", () => {
|
|
32
|
+
const result = checkAllowedUsersGate({
|
|
33
|
+
hasTelegram: true,
|
|
34
|
+
allowedUsersCount: 0,
|
|
35
|
+
authMode: "allowlist",
|
|
36
|
+
insecureAcknowledged: false,
|
|
37
|
+
});
|
|
38
|
+
expect(result.allowed).toBe(false);
|
|
39
|
+
expect(result.reason).toContain("ALLOWED_USERS");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("BLOCKS startup when telegram enabled but allowedUsers empty (pairing mode)", () => {
|
|
43
|
+
// Pairing mode needs allowedUsers[0] as the admin for approval routing.
|
|
44
|
+
// Empty array breaks the whole pairing flow.
|
|
45
|
+
const result = checkAllowedUsersGate({
|
|
46
|
+
hasTelegram: true,
|
|
47
|
+
allowedUsersCount: 0,
|
|
48
|
+
authMode: "pairing",
|
|
49
|
+
insecureAcknowledged: false,
|
|
50
|
+
});
|
|
51
|
+
expect(result.allowed).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("ALLOWS startup when AUTH_MODE=open explicitly", () => {
|
|
55
|
+
const result = checkAllowedUsersGate({
|
|
56
|
+
hasTelegram: true,
|
|
57
|
+
allowedUsersCount: 0,
|
|
58
|
+
authMode: "open",
|
|
59
|
+
insecureAcknowledged: false,
|
|
60
|
+
});
|
|
61
|
+
expect(result.allowed).toBe(true);
|
|
62
|
+
expect(result.warning).toContain("open");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("ALLOWS startup when ALVIN_INSECURE_ACKNOWLEDGED=1", () => {
|
|
66
|
+
const result = checkAllowedUsersGate({
|
|
67
|
+
hasTelegram: true,
|
|
68
|
+
allowedUsersCount: 0,
|
|
69
|
+
authMode: "allowlist",
|
|
70
|
+
insecureAcknowledged: true,
|
|
71
|
+
});
|
|
72
|
+
expect(result.allowed).toBe(true);
|
|
73
|
+
expect(result.warning).toContain("INSECURE");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("ALLOWS startup when telegram is NOT enabled (bot is WebUI-only)", () => {
|
|
77
|
+
// WebUI-only deployments don't have a BOT_TOKEN and don't need
|
|
78
|
+
// ALLOWED_USERS — the gate only applies when hasTelegram === true.
|
|
79
|
+
const result = checkAllowedUsersGate({
|
|
80
|
+
hasTelegram: false,
|
|
81
|
+
allowedUsersCount: 0,
|
|
82
|
+
authMode: "allowlist",
|
|
83
|
+
insecureAcknowledged: false,
|
|
84
|
+
});
|
|
85
|
+
expect(result.allowed).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("reason message mentions ~/.alvin-bot/.env and @userinfobot for operator guidance", () => {
|
|
89
|
+
const result = checkAllowedUsersGate({
|
|
90
|
+
hasTelegram: true,
|
|
91
|
+
allowedUsersCount: 0,
|
|
92
|
+
authMode: "allowlist",
|
|
93
|
+
insecureAcknowledged: false,
|
|
94
|
+
});
|
|
95
|
+
expect(result.reason).toMatch(/\.env|alvin-bot/i);
|
|
96
|
+
expect(result.reason).toMatch(/userinfobot|telegram/i);
|
|
97
|
+
});
|
|
98
|
+
});
|