Files
derp/docs/USAGE.md
user 129121ad26 docs: update docs for v1.1.0 features
Document message truncation, reconnect backoff, dork and wayback
plugins. Update roadmap, tasks, and plugin table.

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

13 KiB

Usage Guide

Running

# From project directory
derp

# With options
derp --config /path/to/derp.toml --verbose

CLI Flags

Flag Description
-c, --config PATH Config file path
-v, --verbose Debug logging
--cprofile [PATH] Enable cProfile, dump to PATH [derp.prof]
-V, --version Print version
-h, --help Show help

Configuration

All settings in config/derp.toml:

[server]
host = "irc.libera.chat"    # IRC server hostname
port = 6697                   # Port (6697 = TLS, 6667 = plain)
tls = true                    # Enable TLS encryption
nick = "derp"                 # Bot nickname
user = "derp"                 # Username (ident)
realname = "derp IRC bot"     # Real name field
password = ""                 # Server password (optional)
sasl_user = ""                # SASL PLAIN username (optional)
sasl_pass = ""                # SASL PLAIN password (optional)
ircv3_caps = [                # IRCv3 capabilities to request
    "multi-prefix",
    "away-notify",
    "server-time",
    "cap-notify",
    "account-notify",
]

[bot]
prefix = "!"                  # Command prefix character
channels = ["#test"]          # Channels to join on connect
plugins_dir = "plugins"       # Plugin directory path
rate_limit = 2.0              # Max messages per second (default: 2.0)
rate_burst = 5                # Burst capacity (default: 5)
admins = []                   # Hostmask patterns (fnmatch), IRCOPs auto-detected

[logging]
level = "info"                # Logging level: debug, info, warning, error

Built-in Commands

Command Description
!ping Bot responds with "pong"
!help List all available commands
!help <cmd> Show help for a specific command
!help <plugin> Show plugin description and its commands
!version Show bot version
!uptime Show how long the bot has been running
!echo <text> Echo back text (example plugin)
!cert <domain> [...] Lookup CT logs for up to 5 domains
!whoami Show your hostmask and admin status
!load <plugin> Hot-load a plugin (admin)
!reload <plugin> Reload a plugin (admin)
!unload <plugin> Unload a plugin (admin)
!admins Show admin patterns and detected opers (admin)
!plugins List loaded plugins with handler counts
!state <action> <plugin> [key] Inspect plugin state store (admin)
!kick <nick> [reason] Kick user from channel (admin)
!ban <mask> Ban a hostmask in channel (admin)
!unban <mask> Remove a ban from channel (admin)
!topic [text] Set or query channel topic (admin)
!mode <mode> [args] Set channel mode (admin)
!dns <target> [type] DNS lookup (A, AAAA, MX, NS, TXT, CNAME, PTR, SOA)
!encode <fmt> <text> Encode text (b64, hex, url, rot13)
!decode <fmt> <text> Decode text (b64, hex, url, rot13)
!hash [algo] <text> Generate hash digests (md5, sha1, sha256, sha512)
!hashid <hash> Identify hash type by format
!defang <ioc> Defang URLs/IPs/domains for safe sharing
!refang <text> Restore defanged IOCs
!revshell <type> <ip> <port> Generate reverse shell one-liner
!cidr <network> Subnet info (range, hosts, mask)
!cidr contains <net> <ip> Check if IP belongs to network
!whois <domain|ip> WHOIS lookup via raw TCP (port 43)
!portcheck <host> [ports] Async TCP port scan (max 20 ports)
!httpcheck <url> HTTP status, redirects, response time
!tlscheck <host> [port] TLS version, cipher, cert details
!blacklist <ip> Check IP against 10 DNSBLs
!rand <mode> [args] Random: password, hex, uuid, bytes, int, coin, dice
!timer <duration> [label] Set countdown timer with notification
!timer list Show active timers
!timer cancel <label> Cancel a running timer
!geoip <ip> GeoIP lookup (city, country, coords, timezone)
!asn <ip> ASN lookup (AS number, organization)
!tor <ip|update> Check IP against Tor exit nodes
!iprep <ip|update> Check IP against Firehol/ET blocklists
!cve <id|search> CVE lookup from local NVD mirror
!opslog <add|list|search|del|clear> Timestamped operational log
!note <set|get|del|list|clear> Per-channel key-value notes
!subdomain <domain> [brute] Subdomain enumeration (crt.sh + DNS)
!headers <url> HTTP header fingerprinting
!exploitdb <search|id|cve|update> Search local Exploit-DB mirror
!payload <type> [variant] Web vuln payload templates
!dork <category|list> [target] Google dork query builder
!wayback <url> [YYYYMMDD] Wayback Machine snapshot lookup

Command Shorthand

Commands can be abbreviated to any unambiguous prefix:

!h           -> !help (unique match)
!pi          -> !ping (unique match)
!p           -> error: ambiguous (ping, plugins)

Exact matches always take priority over prefix matches.

!cert -- Certificate Transparency Lookup

Query crt.sh CT logs to enumerate SSL certificates for domains. Reports totals (expired/valid) and flags domains still serving expired certs.

!cert example.com
!cert example.com badsite.com another.org

Output format:

example.com -- 127 certs (23 expired, 104 valid)
badsite.com -- 45 certs (8 expired, 37 valid) | live cert EXPIRED
broken.test -- error: timeout
  • Max 5 domains per invocation
  • crt.sh can be slow; the bot confirms receipt before querying
  • Live cert check runs only when expired CT entries exist

Admin System

Commands marked as admin require elevated permissions. Admin access is granted via:

  1. IRC operator status -- detected automatically via WHO on channel join
  2. Hostmask patterns -- configured in [bot] admins, fnmatch-style
[bot]
admins = [
    "*!~user@trusted.host",
    "ops!*@*.ops.net",
]

Empty by default -- only IRC operators get admin access unless patterns are configured.

Command Description
!whoami Show your hostmask and admin status
!admins Show configured patterns and detected opers (admin)

Admin-restricted commands: !load, !reload, !unload, !admins, !state, !kick, !ban, !unban, !topic, !mode.

Writing Admin Commands

@command("dangerous", help="Admin-only action", admin=True)
async def cmd_dangerous(bot, message):
    ...

IRCv3 Capability Negotiation

The bot negotiates IRCv3 capabilities using CAP LS 302 during registration. This enables richer features on servers that support them.

Default Capabilities

[server]
ircv3_caps = ["multi-prefix", "away-notify", "server-time",
              "cap-notify", "account-notify"]
Capability Purpose
multi-prefix Better IRCOP/voice detection
away-notify Receive AWAY status changes
server-time Accurate message timestamps
cap-notify Dynamic capability updates
account-notify Account login/logout notices
sasl Auto-added when SASL credentials configured

The bot only requests caps the server advertises. SASL is automatically included when sasl_user and sasl_pass are configured.

Message Tags

IRCv3 message tags (@key=value;...) are parsed automatically and available on the message object as message.tags (a dict[str, str]). Values are unescaped per the IRCv3 spec.

Channel Management

Channel management commands require admin privileges and must be used in a channel (not DM).

!kick <nick> [reason]     Kick a user from the channel
!ban <mask>               Set +b on a hostmask (e.g. *!*@bad.host)
!unban <mask>             Remove +b from a hostmask
!topic [text]             Set topic (empty = query current topic)
!mode <mode> [args]       Set raw MODE on the channel

The bot must have channel operator status for these commands to take effect.

Plugin State Persistence

Plugins can persist key-value data across restarts via bot.state:

bot.state.set("myplugin", "last_run", "2026-02-15")
value = bot.state.get("myplugin", "last_run")
bot.state.delete("myplugin", "last_run")
keys = bot.state.keys("myplugin")
bot.state.clear("myplugin")

Data is stored in data/state.db (SQLite). Each plugin gets its own namespace so keys never collide.

Inspection Commands (admin)

!state list <plugin>      List keys for a plugin
!state get <plugin> <key> Get a value
!state del <plugin> <key> Delete a key
!state clear <plugin>     Clear all state for a plugin

Local Databases (Wave 3)

Several plugins rely on local data files in the data/ directory. Use the update script or in-bot commands to populate them.

Data Update Script

./scripts/update-data.sh                        # Update all feeds
MAXMIND_LICENSE_KEY=xxx ./scripts/update-data.sh # Include GeoLite2

The script is cron-friendly (exit 0/1, quiet unless NO_COLOR is unset).

In-Bot Updates

!tor update          # Download Tor exit node list
!iprep update        # Download Firehol/ET blocklist feeds
!cve update          # Download NVD CVE feed (slow, paginated)

Data Directory Layout

data/
  GeoLite2-City.mmdb    # MaxMind GeoIP (requires license key)
  GeoLite2-ASN.mmdb     # MaxMind ASN (requires license key)
  tor-exit-nodes.txt    # Tor exit node IPs
  iprep/                # Firehol/ET blocklist feeds
    firehol_level1.netset
    firehol_level2.netset
    et_compromised.ipset
    ...
  nvd/                  # NVD CVE JSON files
    nvd_0000.json
    ...

GeoLite2 databases require a free MaxMind license key. Set MAXMIND_LICENSE_KEY when running the update script.

Plugin Management

Plugins can be loaded, unloaded, and reloaded at runtime without restarting the bot.

!load crtsh          # Hot-load a new plugin from plugins/
!reload crtsh        # Reload a changed plugin
!unload crtsh        # Remove a plugin and all its handlers
!plugins             # List loaded plugins with handler counts

The core plugin cannot be unloaded (prevents losing !load/!reload), but it can be reloaded.

Writing Plugins

Create a .py file in the plugins/ directory:

from derp.plugin import command, event

@command("hello", help="Greet the user")
async def cmd_hello(bot, message):
    """Handler receives bot instance and parsed Message."""
    await bot.reply(message, f"Hello, {message.nick}!")

@event("JOIN")
async def on_join(bot, message):
    """Event handlers fire on IRC events (JOIN, PART, QUIT, etc.)."""
    if message.nick != bot.nick:
        await bot.send(message.target, f"Welcome, {message.nick}")

Plugin API

The bot object provides:

Method Description
bot.send(target, text) Send message to channel or nick
bot.reply(msg, text) Reply to source (channel or PM)
bot.action(target, text) Send /me action
bot.join(channel) Join a channel
bot.part(channel [, reason]) Leave a channel
bot.quit([reason]) Disconnect from server
bot.kick(channel, nick [, reason]) Kick a user
bot.mode(target, mode_str, *args) Set a mode
bot.set_topic(channel, topic) Set channel topic
bot.state Plugin state store (get/set/delete/keys/clear)

The message object provides:

Attribute Description
message.nick Sender's nickname
message.prefix Full nick!user@host prefix
message.command IRC command (PRIVMSG, JOIN, etc.)
message.target First param (channel or nick)
message.text Trailing text content
message.is_channel Whether target is a channel
message.params All message parameters
message.tags IRCv3 message tags (dict)

Message Truncation

Messages are automatically split at UTF-8 safe boundaries to comply with the IRC 512-byte line limit (RFC 2812). The overhead of PRIVMSG <target> : and \r\n is accounted for, so plugins can send arbitrarily long text without worrying about protocol limits.

Reconnect Backoff

On connection loss, the bot reconnects with exponential backoff and jitter:

  • Initial delay: 5 seconds
  • Growth: doubles each attempt (5s, 10s, 20s, 40s, ...)
  • Cap: 300 seconds (5 minutes)
  • Jitter: +/- 25% to avoid thundering herd
  • Resets to 5s after a successful connection

!dork -- Google Dork Query Builder

Generate Google dork queries for a target domain. Template-based, no HTTP requests -- just outputs the query string for manual use.

!dork list                    List all dork categories
!dork admin example.com       Admin/login panel dorks
!dork files example.com       Exposed document dorks

Categories: admin, backup, cloud, config, creds, dirs, errors, exposed, files, login.

!wayback -- Wayback Machine Lookup

Check the Wayback Machine for archived snapshots of a URL.

!wayback example.com                Check latest snapshot
!wayback example.com/page 20240101  Check snapshot near a date

Auto-prepends https:// if no scheme is provided. Uses the Wayback Machine availability API.