Commit Graph

55 Commits

Author SHA1 Message Date
user ffa75670e2 fix: use mTLS client cert to bypass PoW on flaskpaste
When secrets/flaskpaste/derp.crt and derp.key are present, load them
into the SSL context for mutual TLS auth and skip the PoW challenge
entirely. Fall back to PoW only when no client cert is available.
2026-02-16 23:13:09 +01:00
user 3cdc00c285 feat: add flaskpaste plugin with paste/shorten commands
- PoW-authenticated paste creation and URL shortening via FlaskPaste
- !paste <text> creates a paste, !shorten <url> shortens a URL
- Module-level shorten_url/create_paste helpers for cross-plugin use
- Alert plugin auto-shortens URLs in announcements and history output
- Custom TLS CA cert support via secrets/flaskpaste/derp.crt
- No SOCKS proxy -- direct urllib.request to FlaskPaste instance
2026-02-16 23:10:59 +01:00
user 35acc744ac fix: use DNS-over-HTTPS with provider rotation for emailcheck
Tor exit nodes poison plain DNS on port 53 and MITM some HTTPS
connections. Replace raw TCP DNS with DoH (Google, Cloudflare, Quad9)
and retry up to 5 times across providers to find a clean exit node.
MX results are now sorted by priority.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 22:40:43 +01:00
user e8d803abe6 fix: account for server prefix in IRC line splitting
The 512-byte IRC limit includes the :nick!user@host prefix the server
prepends when relaying. Reserve 64 bytes for it and prefer splitting at
space boundaries instead of mid-word. Also strip the command prefix and
"Commands:" label from help output to keep the listing compact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 22:02:52 +01:00
user eb37fef730 feat: add jwt, mac, abuseipdb, virustotal, and emailcheck plugins
v2.0.0 sprint 1 -- five standalone plugins requiring no core changes:

- jwt: decode JWT header/payload, flag alg=none/expired/nbf issues
- mac: IEEE OUI vendor lookup, random MAC generation, OUI download
- abuseipdb: IP reputation check + abuse reporting (admin) via API
- virustotal: hash/IP/domain/URL lookup via VT APIv3, 4/min rate limit
- emailcheck: SMTP RCPT TO verification via MX + SOCKS proxy (admin)

Also adds update_oui() to update-data.sh and documents all five
plugins in USAGE.md and CHEATSHEET.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 21:04:43 +01:00
user 8e2b94fef0 feat: add 11 alert backends and fix PyPI/DEV.to search
Add Wikipedia, Stack Exchange, GitLab, npm, PyPI, Docker Hub,
arXiv, Lobsters, DEV.to, Medium, and Hugging Face backends to
the alert plugin (16 -> 27 total). Fix PyPI backend to use RSS
updates feed (web search now requires JS challenge). Fix DEV.to
to use public articles API (feed_content endpoint returns empty).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:07:01 +01:00
user 34d5dd6f8d fix: resolve YouTube channel ID via InnerTube for video URLs
Video URLs (watch, shorts, embed, youtu.be) now resolve the channel
ID through the InnerTube player API -- a small JSON POST instead of
fetching the full 1MB watch page. Much more resilient to transient
proxy failures. Page scraping remains as fallback for handle URLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 18:39:32 +01:00
user daa3370433 feat: add short IDs to alert results with !alert info command
Each alert result gets a deterministic 8-char base36 ID derived from
backend:item_id. IDs appear in announcements and history, and can be
looked up with !alert info <id> for full details. Existing rows are
backfilled on startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:20:56 +01:00
user 5ded8186dd feat: add Hacker News and GitHub backends to alert plugin
Hacker News (hn) uses Algolia search_by_date API for stories,
appends point count to title, falls back to HN discussion URL
when no external link. GitHub (gh) searches repositories sorted
by recently updated, shows star count and truncated description.
Both routed through SOCKS5 proxy via _urlopen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:10:00 +01:00
user f0b198d98a feat: add Bluesky, Lemmy, Odysee, and Archive.org alert backends
Bluesky (bs) searches public post API, constructs bsky.app URLs
from at:// URIs. Lemmy (ly) queries 4 instances (lemmy.ml,
lemmy.world, programming.dev, infosec.pub) with cross-instance
dedup. Odysee (od) uses LBRY JSON-RPC claim_search for video,
audio, and documents with lbry:// to odysee.com URL conversion.
Archive.org (ia) searches via advanced search API sorted by date.
All routed through SOCKS5 proxy via _urlopen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:07:09 +01:00
user 52c49609b3 feat: add Kick, Dailymotion, and PeerTube backends to alert plugin
Kick (kk) searches channels and livestreams via public search API.
Dailymotion (dm) queries video API sorted by recent. PeerTube (pt)
searches across 4 federated instances with per-instance timeout.
All routed through SOCKS5 proxy via _urlopen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:01:21 +01:00
user 80677343bf feat: add DuckDuckGo and Google News backends to alert plugin
DuckDuckGo (dg) searches via HTML lite endpoint with HTMLParser,
resolves DDG redirect URLs to actual targets. Google News (gn)
queries public RSS feed, parses RFC 822 dates. Both routed through
SOCKS5 proxy via _urlopen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:51:52 +01:00
user e70c22a510 feat: search SearXNG across categories with day filter
Query general, news, videos, and social media categories
separately with time_range=day. Dedup results by URL across
categories to avoid announcing the same item twice.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:44:55 +01:00
user f84723f66d feat: add Reddit and Mastodon backends to alert plugin
Search Reddit posts (rd) via JSON API and Mastodon hashtag
timelines (ft) across 4 fediverse instances. Both public,
no auth required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:42:06 +01:00
user 83a1d37b98 feat: persist invite-joined channels for auto-rejoin on connect
When the bot accepts an admin INVITE, the channel is stored in
bot.state under chanmgmt/autojoin:<channel>. On reconnect, persisted
channels are rejoined alongside configured ones. If the bot is kicked,
the channel is removed from the auto-rejoin list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:22:24 +01:00
user 122785b1f3 feat: persist alert results to SQLite history table
Matched results were announced then discarded. Add a dedicated SQLite
database (data/alert_history.db) to store every announced result with
channel, alert name, backend, title, URL, date, and timestamp. Add
!alert history <name> [n] subcommand to query recent results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:09:01 +01:00
user 181d6dbfad fix: call YouTube API directly, announce all matched results
YouTube InnerTube is a public API -- no need to route through SOCKS5
proxy, which was causing SSL EOF errors on every poll. Switch to
direct urllib.request.urlopen.

Remove _MAX_ANNOUNCE cap; all matched results are now announced
individually instead of truncating with "... and N more".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:04:15 +01:00
user 6d6f4e7343 fix: handle null publishedDate from SearXNG results
SearXNG can return "publishedDate": null, which bypasses the default
value in dict.get() and passes None to _parse_date / re.search.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 21:42:07 +01:00
user 604a0a5830 feat: display published date in alert announcements
Extract dates from multiple sources:
- SearXNG: publishedDate field from search results
- YouTube: publishedTimeText from InnerTube response
- OG fallback: article:published_time, og:updated_time, date,
  dc.date, dcterms.date, sailthru.date meta tags

Date is shown as (YYYY-MM-DD) or relative time after the tag prefix.
OG tags are fetched for date even when title/URL already matched.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 21:30:48 +01:00
user e36ec350f5 feat: check og:title/og:description for keyword match in alerts
When a search result's title/URL doesn't contain the keyword, fetch
the page's first 64 KB and parse og:title and og:description meta
tags. If the keyword appears there, the result is announced. Prefers
og:title as display title when it's richer than the search result
title.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 21:28:48 +01:00
user 0d5855dda3 fix: filter alert results to require keyword match in title/URL
Search backends return loosely relevant results. Now only announces
items where the keyword actually appears in the title or URL
(case-insensitive). All results are still marked as seen to prevent
re-checking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 21:27:03 +01:00
user 118cf0de21 fix: centralize retry logic in proxy transport layer
Add exponential-backoff retry (3 attempts) for transient SSL,
connection, timeout, and OS errors to all three proxy functions:
urlopen, create_connection, open_connection. Remove per-plugin
retry from alert.py since transport layer now handles it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 18:55:21 +01:00
user 6d86e8d7f8 fix: retry transient SSL/connection errors in alert backends
Add retry loop (3 attempts, exponential backoff) for SSLError,
ConnectionError, TimeoutError, and OSError in alert poll cycle.
Non-transient errors fail immediately. Also fixes searx test
mocks to match direct urlopen usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 18:51:28 +01:00
user f046cced28 fix: use public SearXNG URL without proxy
Switch to searx.mymx.me (public domain) for SearXNG queries
without routing through SOCKS5 proxy. Internal address is not
reachable from the container network.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 18:28:29 +01:00
user b973635445 fix: route SearXNG direct via static route, drop proxy
SearXNG instance at 192.168.122.119 is reachable via grokbox
static route -- no need to tunnel through SOCKS5. Reverts searx
and alert plugins to stdlib urlopen for SearXNG queries. YouTube
and Twitch in alert.py still use the proxy. Also removes cprofile
flag from docker-compose command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 17:52:43 +01:00
user 29e77f97b2 fix: route searx and alert SearXNG traffic through SOCKS5 proxy
Both plugins called urllib.request.urlopen directly, bypassing the
proxy. Switch to derp.http.urlopen and update the SearXNG endpoint
to the public domain (searx.mymx.me). Update test mocks to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:56:45 +01:00
user d5866a9867 fix: route blacklist and subdomain DNS through Tor resolver
Both plugins duplicated wire-format helpers and queried the system
resolver on port 53. Switch to shared derp.dns helpers and point
queries at the local Tor DNS resolver (127.0.0.1:9053) so lookups
go through Tor like all other outbound traffic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:16:57 +01:00
user 26063a0e8f feat: add TCP DNS plugin with SOCKS5 proxy support
Extract shared DNS wire-format helpers into src/derp/dns.py so both
the UDP plugin (dns.py) and the new TCP plugin (tdns.py) share the
same encode/decode/build/parse logic.

The !tdns command routes queries through the SOCKS5 proxy via
derp.http.open_connection, using TCP framing (2-byte length prefix).
Default server: 1.1.1.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:09:35 +01:00
user 1bdba0ea06 feat: route raw TCP traffic through SOCKS5 proxy
Add create_connection and open_connection helpers to the shared proxy
module, covering portcheck, whois, tlscheck, and crtsh live-cert check.
UDP-based plugins (dns, blacklist, subdomain) stay direct.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:01:17 +01:00
user 97bbc6a825 feat: route plugin HTTP traffic through SOCKS5 proxy
Add PySocks dependency and shared src/derp/http.py module providing
proxy-aware urlopen() and build_opener() that route through
socks5h://127.0.0.1:1080. Subclassed SocksiPyHandler passes SSL
context through to HTTPS connections.

Swapped 14 external-facing plugins to use the proxied helpers.
Local-only traffic (SearXNG, raw DNS/TLS sockets) stays direct.
Updated test mocks in test_twitch and test_alert accordingly.
2026-02-15 15:53:49 +01:00
user 10f62631be feat: add SearX search plugin and alert backend
Add standalone !searx command for on-demand SearXNG search (top 3 results).
Add SearX as a third backend (sx) to the alert plugin for keyword monitoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:28:00 +01:00
user 8fd6393273 feat: add keyword alert subscription plugin
Search keywords across YouTube (InnerTube) and Twitch (GQL)
simultaneously, announcing new results per channel. Supports
add/del/list/check subcommands with per-platform seen lists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:16:29 +01:00
user 50fb8015cd feat: add Twitch livestream notification plugin
Poll Twitch streamers via public GQL endpoint and announce
offline-to-live transitions in IRC channels. Tracks stream ID
to avoid re-announcing the same stream.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 14:50:30 +01:00
user 3955935da4 feat: add YouTube channel follow plugin
Follow YouTube channels via Atom feeds with !yt follow/unfollow/list/check.
Resolves any YouTube URL to a channel ID, polls for new videos, and
announces them in IRC channels.
2026-02-15 14:34:20 +01:00
user 6b7572defc feat: auto-join channels on admin invite 2026-02-15 13:52:15 +01:00
user 125a4c5d4d feat: add per-channel RSS feed subscription plugin
Subscribe RSS/Atom feeds to IRC channels with periodic polling,
new-item announcements, deduplication, and persistence across restarts.
Supports conditional HTTP requests (ETag/Last-Modified), automatic
backoff on errors, and per-channel feed limits.
2026-02-15 13:36:23 +01:00
user f888faf2bd feat: add calendar-based reminders (at/yearly) with persistence
Calendar reminders use bot.state (SQLite KV) for persistence across
restarts. Supports one-shot at specific date/time and yearly recurring
reminders with leap day handling. Restored automatically on connect
via 001 event handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:39:42 +01:00
user 021a0ddbe3 test: comprehensive remind plugin tests with IndexError fix
Expand test coverage from 23 pure helper tests to 53 tests covering
the full plugin: _cleanup, _remind_once, _remind_repeat, and the
complete cmd_remind handler (usage, oneshot, repeating, list, cancel,
target routing). Fix IndexError on `!remind every` with no arguments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:17:31 +01:00
user 70d203f96e feat: add remind plugin with one-shot and repeating reminders
Supports duration parsing (5m, 1h30m, 2d12h), short hex IDs for
tracking, list/cancel subcommands, and repeating intervals via
`!remind every <duration> <text>`. Includes 23 unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:09:34 +01:00
user 32197d71ae feat: add username enumeration plugin
Cross-platform username OSINT across ~25 services (GitHub, GitLab,
Reddit, Docker Hub, Keybase, Dev.to, Twitch, Steam, etc).  Hybrid
approach using HTTP status probes, JSON APIs, and body search.
8 parallel workers via ThreadPoolExecutor, 20s overall timeout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 04:47:23 +01:00
user 9db02212b7 fix: filter help output by per-channel plugin config
!help now only lists commands from plugins allowed in the current
channel. !help <cmd> and !help <plugin> return "unknown" for
filtered plugins. PMs remain unrestricted.
2026-02-15 04:30:28 +01:00
user b48c289403 feat: add wayback plugin (Wayback Machine lookup)
Query Wayback Machine availability API via urllib + executor.
Supports optional timestamp parameter for date-targeted lookups.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 03:27:13 +01:00
user 9afde4e092 feat: add dork plugin (Google dork query builder)
Template-based Google dork categories for recon. No HTTP calls,
no external deps. Supports 10 categories (admin, files, dirs, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 03:27:10 +01:00
user f86cd1ad49 feat: add IRCv3 cap negotiation, channel management, state persistence
Implement CAP LS 302 flow with configurable ircv3_caps list, replacing
the minimal SASL-only registration. Parse IRCv3 message tags (@key=value)
with proper value unescaping. Add channel management plugin (kick, ban,
unban, topic, mode) and bot API methods. Add SQLite key-value StateStore
for plugin state persistence with !state inspection command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 03:07:06 +01:00
user 4a2960b288 feat: add exploitdb and payload plugins, complete wave 4
ExploitDB: search local exploit-db CSV mirror by keyword, EDB ID,
or CVE identifier. In-bot update command downloads the latest CSV
from GitLab. Also added to the update-data.sh script.

Payload: built-in template library with 52 payloads across 6
categories (sqli, xss, ssti, lfi, cmdi, xxe). Supports browsing,
numeric index, and keyword search within categories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:54:38 +01:00
user e1b57e1764 feat: add wave 4 plugins (opslog, note, subdomain, headers)
Opslog: timestamped operational log per channel with add, list,
search, and delete. SQLite-backed, admin-only clear.

Note: persistent per-channel key-value store with set, get, del,
list, clear. SQLite-backed, admin-only clear.

Subdomain: enumeration via crt.sh CT log query with optional DNS
brute force using a built-in 80-word prefix wordlist. Resolves
discovered subdomains concurrently.

Headers: HTTP header fingerprinting against 50+ signature patterns.
Detects servers, frameworks, CDNs, and security headers (HSTS, CSP,
XFO, etc).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:48:16 +01:00
user 19f54da3cf fix: replace dead firehol feeds, fix arithmetic under set -e
Replace bruteforcelogin and bi_any_2_30d (404) with dshield and
spamhaus_drop. Guard ((var++)) with || true to prevent set -e from
killing the script when the pre-increment value is 0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:41:32 +01:00
user 23b4d6f2a4 feat: add wave 3 local database plugins
GeoIP and ASN lookup via MaxMind GeoLite2 mmdb, Tor exit node check
against local bulk exit list, IP reputation via Firehol/ET blocklist
feeds, and CVE lookup against local NVD JSON mirror.

Includes cron-friendly update script (scripts/update-data.sh) for all
data sources and make update-data target. GeoLite2 requires a free
MaxMind license key; all other sources are freely downloadable.

Plugins: geoip, asn, torcheck, iprep, cve
Commands: !geoip, !asn, !tor, !iprep, !cve

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:38:13 +01:00
user f96224afb1 feat: add admin/owner permission system
Hostmask-based admin controls with automatic IRCOP detection via WHO.
Permission enforcement in the central dispatch path denies restricted
commands to non-admins. Includes !whoami and !admins commands, marks
load/reload/unload as admin-only.

Also lands previously-implemented SASL PLAIN auth, token-bucket rate
limiting, and CTCP VERSION/TIME/PING responses that were staged but
uncommitted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:26:27 +01:00
user 530f33be76 feat: add wave 2 plugins and --cprofile CLI flag
Add 7 new pure-stdlib plugins: whois (raw TCP port 43), portcheck
(async TCP connect scan with internal-net guard), httpcheck (HTTP
status/redirects/timing), tlscheck (TLS version/cipher/cert inspect),
blacklist (parallel DNSBL check against 10 RBLs), rand (password/hex/
uuid/bytes/int/coin/dice), and timer (async countdown notifications).

Add --cprofile flag to CLI for profiling bot runtime. Update all docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:58:47 +01:00