Commit graph

93 commits

Author SHA1 Message Date
Rosie Val
a9cdef8a1b Fix dashboard security issues: path traversal, OAuth CSRF, exposed bind, stale cache
- _serve_spa built file paths directly from the URL with no containment
  check, on a route reachable with zero authentication. Verified the exact
  exploit (percent-encoded traversal) reproduces path escape, then fixed by
  resolving the path and requiring it stay under WEB_DIR before ever
  touching the filesystem.
- OAuth state was generated and handed to the client but never bound
  server-side or checked on callback — classic login CSRF/session fixation.
  Now bound to a short-lived httponly cookie set during login and verified
  (constant-time) on callback.
- Default bind changed from 0.0.0.0 to 127.0.0.1 — loading this cog with
  zero config shouldn't expose a web server on every interface before the
  owner has even run setup. `[p]evedash host 0.0.0.0` still opts back in.
- _check_guild_access and the callback's guild-membership check relied
  solely on the member cache, which can wrongly deny a real admin if the
  Members intent hasn't warmed for that guild yet. Both now fall back to a
  live fetch on cache miss (per-guild for the single-guild endpoints,
  bot-wide only in the rare one-time login path — deliberately not done in
  the bulk guild-list endpoint, where that fallback would mean an API call
  per guild on every page load).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 00:08:12 +01:00
Rosie Val
5e41658d7d Re-enable Report/Delete/Profile context menus, remove Bookmark, fix reports
Re-enabled the "Report to Wormhole", "Delete from Network", and "Wormhole
Profile" context menus (previously disabled entirely). Removed "Bookmark
(Wormhole)" per request — the prefix `wh bm list`/`clear` commands are
untouched, but note this was the only way to *add* a bookmark, so that
feature is now list/clear-only for existing entries.

Wormhole Profile is now considerably richer: account creation date, total
cross-network message count, global-ban status, and per-network karma/
server-count/muted/banned status, sorted busiest-network-first.

Fixed both report-creation paths (the "Report to Wormhole" context menu's
modal, and `wh report msg`): report_counter was read before the config lock
and written after, so concurrent reports could collide on the same id with
the counter never advancing. Now computed and saved atomically inside the
lock. Also gave both paths full parity — message id, jump link, and a real
content preview (the context-menu path previously stored `hash()` of the
content, which is randomized per-process in Python 3 and useless for
anything; the prefix-command path never even recorded who wrote the
message). `wh report view` now surfaces all of it.

Also added the "Find Origin" context menu (right-click a message -> find
its true source server/channel/author across the network) as a separate,
complementary feature to Profile — not a replacement.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 00:02:49 +01:00
Rosie Val
ece196748c Add Wormhole 'Find Origin' right-click context menu
Right-click any relayed message -> Apps -> Find Origin resolves it back to
the true source: origin server (name + ID), channel, author (name + ID),
message ID, and a jump link. Uses the existing message_map reverse lookup,
falling back to the same brute-force search across the network's member
channels that _ctx_delete_message/wh mod nuke already rely on when the
relay map doesn't have a direct answer. Mod-gated (deanonymizes real
identity across servers). Registered independently of the existing bulk
Report/Bookmark/Delete/Profile context-menu registration, which is
currently disabled — left that decision alone rather than reviving it as
a side effect.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 23:53:57 +01:00
Rosie Val
4471c21386 Fix RubyLogging crashes: __slots__ attribute injection and dead config key
_handle_message_delete_with_cache tried to stash cached attachment data as
message._cached_attachments, but discord.Message uses __slots__ and rejects
arbitrary attribute assignment — this crashed on_message_delete every time a
deleted message had cached attachments (42 times in 48h in production).
Fixed by looking the cache up by message id in self._attachment_cache
instead (same data, same spot _build_embed already checked, just accessed
legally), deferring eviction until after it's actually used.

Also removed two dead `accent = await config.accent_color()` calls —
accent_color was never a registered config key, so both crashed
unconditionally whenever the attachment-preservation feature actually ran,
and the fetched value was never even used afterward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 23:50:10 +01:00
Rosie Val
6dfefbe6dc Remove redundant manual send_help from command groups
redbot.core.commands.Group has autohelp=True by default, and its invoke()
override already calls ctx.send_help() unconditionally whenever no
subcommand matches. Manually calling it too (the
`if ctx.invoked_subcommand is None: await ctx.send_help(ctx.command)`
pattern) caused help to be sent twice on every bare group invocation
across GhostWipe, ImageVault, and Affiliates. Verified against Red's
actual Group.invoke() source before fixing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 23:34:04 +01:00
Rosie Val
940c15c27d Add Affiliates cog: Ping on Join, affiliate board, and DM affiliates
POJ mentions new human members in configured channels then auto-deletes
the ping after a configurable delay. The affiliate board is a staff-managed,
persistent plain-text listing (modal to add, select+confirm to remove),
10 entries per message with a new message per additional page, always
kept in sync in real time and recreated if a page is ever deleted. DM
Affiliates mirrors the same management on a fully separate list sent to
new members via DM on join.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 23:21:19 +01:00
Rosie Val
fdf41cfcbc GhostWipe report: chronological order, mobile layout, Ruby branding
Messages within each channel now sort oldest-first (history()/purge()
return newest-first, which read backwards). Added a real mobile layout:
below 700px the sidebar stacks above the message view and its channel
list becomes a horizontally-scrolling chip strip instead of a cramped
vertical column. Report title/footer and the Discord log embeds now
carry Ruby branding alongside the GhostWipe module name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 18:41:36 +01:00
Rosie Val
039e85d65a Fix GhostWipe report: render server-side, embed avatar, cut purge latency
The HTML report was entirely JavaScript-driven — stats/sidebar/messages only
populated from an embedded JSON blob after load. Viewers that don't execute
scripts (or block network access for local files) showed a blank 0/0/0
skeleton even though the purge worked correctly. Now every stat, the channel
list, and every message are rendered directly into the HTML by Python; JS is
only a progressive enhancement for search. Avatar is downloaded and embedded
as a base64 data URI instead of a live CDN link, so it always renders. Also
parallelized archived-thread lookups, skip the rate-limit pause on channels
with nothing to delete, and post an immediate placeholder log message that
gets edited with the final results instead of the channel sitting silent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 18:32:30 +01:00
Rosie Val
0e26fe311f Add ImageVault cog: auto-delete images, re-host in vault channel, retrieve on request
Watches configured channels for image attachments, reposts each image (with
attribution and message text) into a staff-only vault channel, then deletes
the original. Retrieval re-fetches the vault message fresh each time so
there's no stale-link problem, and spoiler tags round-trip intact. Access
to config is admin-only; retrieval defaults to open for everyone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 18:06:20 +01:00
Rosie Val
309d0e3ea7 Add GhostWipe cog: auto-purge departing member's messages + HTML audit log
Deletes a member's messages server-wide the moment they leave, are kicked,
or are banned (all fire on_member_remove; audit log classifies which).
Generates a self-contained HTML report with channel-switching, search, and
attachment previews, alongside per-guild config for triggers, exemptions,
scan scope, dry-run mode, and report retention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 17:52:18 +01:00
Rosie Val
6cc7f8e494
Add files via upload 2026-07-22 16:13:03 -04:00
Rosie Val
8459ecdcf7
Delete wormhole/commands/moderation.py 2026-07-22 16:12:54 -04:00
Rosie Val
7875ecea95
Add files via upload 2026-07-22 16:07:35 -04:00
Rosie Val
e211ce2950
Delete wormhole/utils.py 2026-07-22 16:07:26 -04:00
Rosie Val
e8bcbb8e24
Add files via upload 2026-07-22 16:07:09 -04:00
Rosie Val
76889459fa
Delete wormhole/listeners/relay.py 2026-07-22 16:06:56 -04:00
Rosie Val
1fbb2657fd fix: add network validation and logging to all settings commands
- Added null check for network existence in all wh set commands
- All setting changes now log to the log channel with descriptive titles
- Prevents KeyError crashes on invalid network names
- Improves audit trail for administrator actions
2026-07-21 22:34:31 -04:00
Rosie Val
0cad208455 fix: disable mention parsing in relay to prevent unintended pings
- Add `allowed_mentions=discord.AllowedMentions(parse=[])` to all webhook and channel sends
- Prevents users from being pinged when replies are relayed across the network
- Fixes issue where reply context could trigger unintended mentions across all servers
- Applies to webhook sends (primary and fallback) and embed/compact relay modes
2026-07-21 21:50:06 -04:00
Omega Launcher
814b0e79e9 fix(support): remove core commands in setup before cog loads
Remove Red's built-in contact and dm commands in setup() before the Support
cog loads to prevent command registration conflicts. Commands are stored and
restored in teardown() when the cog unloads.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-06-12 17:49:07 +01:00
Omega Launcher
26b1bf9253 feat(support): add modernized contact/dm system replacing Red core commands
Add comprehensive Support cog that automatically disables and replaces Red's
built-in contact and dm commands with enhanced, feature-rich versions.

Features:
- Command override mechanism (disables core commands on load, restores on unload)
- Multi-category support system with dedicated channels
- Custom emojis, greetings, and descriptions per category
- User blocking/unblocking system
- Comprehensive logging to dedicated log channel
- Anonymous mode for staff replies
- Enhanced embed formatting
- Category selection dropdown UI
- Staff control buttons (Close Thread, Block User)
- Reply modal for staff responses
- Background thread cleanup task

Commands:
- [p]contact - Enhanced contact command (DM only)
- [p]dm - Enhanced DM command with logging
- [p]supportset - 15 admin configuration commands

Documentation:
- README.md - Full documentation (7.9K)
- QUICKSTART.md - Quick setup guide (2.5K)
- EXAMPLES.md - Configuration examples (8.1K)
- TECHNICAL.md - Technical docs (8.6K)
- CHANGELOG.md - Version history
- test_override.py - Override mechanism reference

Technical:
- 625 lines of code
- 33 async functions
- Full type hints
- Config-based data storage
- Red 3.5.0+ compatible
- Follows NexusCore patterns

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-06-12 17:45:13 +01:00
root
2f97926ca6 fix(wormhole): remove wait_until_ready() from _init() to prevent load timeout
Root cause: _init() was blocking on wait_until_ready() for up to 30 seconds,
causing Red's package load to timeout. Red then reports 'Failed to load
package wormhole (timeout)' but the cog is actually partially loaded,
causing 'already loaded' errors on retry.

Timeline:
1. [p]load wormhole starts
2. setup() calls bot.add_cog(cog) ✓
3. setup() calls await cog._init()
4. _init() blocks on wait_until_ready() for 30s
5. Red's load timeout (30s) triggers
6. Red reports 'timeout' but cog is registered
7. [p]load wormhole again → 'already loaded' error

Solution: Remove wait_until_ready() from _init() since:
- Bot is already ready when cogs load on startup
- Background loops have their own wait_until_ready() calls
- _init() shouldn't block setup()

Background loops still wait_until_ready() independently (correct behavior).

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:43:46 +00:00
root
6fd48e93af fix(wormhole): rename cog class to WormholeV4 to bypass stale registration
Problem: Red's internal state has stale 'Wormhole' cog registrations from
previous versions (both identifier 7730187301 and 928374650), causing
'Cog named Wormhole already loaded' errors even on fresh bot starts.

Root cause: Multiple config identifiers registered under same cog name:
  - wormhole: {'wormhole': {}}  (old lowercase)
  - Wormhole: {'7730187301': {}, '928374650': {}}  (two identifiers!)

Solution: Rename cog class Wormhole → WormholeV4 to bypass all stale
registration state. This gives a clean slate without requiring users to
manually purge config data.

Changes:
- class Wormhole → class WormholeV4 in core.py
- Updated __init__.py import and setup()
- Config identifier unchanged (928374650)

This completely sidesteps the phantom load bug without touching user data.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:38:56 +00:00
root
0c41ae0b9f feat(wormhole): disable context menus to eliminate load issues
Problem: Context menus persist in Discord's command tree even after bot
shutdown, causing 'already loaded' errors on restart. The idempotent
registration fix helped but added complexity.

Solution: Disable context menus entirely. All functionality remains
available via slash/prefix commands:
  - Report: /wh report message [msg_id] [reason]
  - Bookmark: /wh bookmark save [msg_id]
  - Delete: /wh delete [msg_id] (staff only)
  - Profile: /wh profile [user]

Changes:
- Commented out _register_context_menus() call in _init()
- Kept registration/callback code for future reference
- Simplified cog_unload() - no context menus to remove

Benefits:
- No command tree registration complexity
- Clean reload every time
- No phantom 'already loaded' state
- Simpler cog lifecycle

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:35:27 +00:00
root
c8bc14fb42 fix(wormhole): make context menu registration idempotent
Problem: If bot crashes or shuts down ungracefully, context menus stay
registered in Discord's command tree. On restart, add_command() fails
with 'already loaded' error.

Solution: Remove existing context menus before registering new ones.
This makes registration idempotent (safe to run multiple times).

Changes:
- _register_context_menus() now removes existing menus first
- Wrapped in try/except to handle 'not found' gracefully
- Ensures clean reload even after ungraceful shutdown

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:33:09 +00:00
root
15eb047d15 chore(wormhole): remove archived monolith - not needed in repo
The old monolithic file is not needed in version control.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:27:08 +00:00
root
dc695a43ed chore(wormhole): archive old monolithic wormhole.py for reference
Keeping the 4,782-line v3.4.6 monolith as wormhole.py.old for:
- Historical reference
- Rollback safety
- Migration verification

This file is NOT loaded by the cog - it's purely archival.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:26:42 +00:00
root
44d7f79c13 fix(wormhole): fix persistence bug and finalize v4.0.0 modular architecture
BREAKING: Removed obsolete monolithic wormhole.py (4,782 lines)
The v4.0.0 modular architecture was already implemented but the old
file was still present causing confusion.

Fixes:
- Fix context menu cleanup in cog_unload (add type parameter)
- Remove obsolete wormhole.py monolith (archived as .old)
- Context menus now properly unregister on reload

Architecture:
- core.py (731 lines) - main cog class
- commands/ (14 modules, 2,645 lines) - command mixins
- listeners/ (3 modules) - event handlers
- models/ (3 modules) - data structures
- services/ (1 module) - business logic
- ui/ (2 modules) - Discord UI components

Documentation:
+ ARCHITECTURE.md - design overview and history
+ MODULE_MAP.md - developer quick reference

This fixes the "already loaded" phantom state bug where wormhole
wouldn't persist through restarts and required double-loading.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-26 16:26:03 +00:00
root
3aeb656633 feat(rubylogging): add attachment re-upload to preserve deleted images permanently
**The Problem:**
Discord CDN URLs (even proxy URLs) expire after message deletion, so image
previews in logs would show as broken after a few minutes.

**The Solution:**
- New "reupload" feature (enabled by default) downloads and re-uploads attachments
- Deleted images/GIFs are permanently preserved in the log channel
- Works with aiohttp to download attachments asynchronously
- Attaches files directly to log message (up to 10 per message)

**Features:**
- `[p]rlog attachments reupload` - Toggle re-uploading on/off
- Downloads images when message is deleted
- Re-uploads as Discord Files (permanent storage)
- Falls back to URL embedding if download fails
- Shows status in settings display

**Improvements:**
- Use proxy URLs throughout for better persistence
- Pass cached attachments through message object
- Better file extension detection (.png, .jpg, .jpeg, .gif, .webp)
- Track ephemeral attachments
- Exception handling for download failures

**Trade-offs:**
- Uses bandwidth to download/upload
- Files become permanent in log channel
- Worth it for permanent image preservation!

Images and GIFs now remain visible in logs forever! 🖼️

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 22:11:49 +00:00
root
645a8f6985 fix(rubylogging): eliminate duplicate logs and add image previews
**Fixed Duplicate Logs:**
- Skip registering generic handlers for message_delete and bulk_delete
- These events are now handled only by specialized attachment handlers
- Eliminates 2x delete logs and 3x edit logs issue

**Added Image Previews:**
- Deleted messages now show image previews in the embed
- Cached attachments display the actual image/GIF
- Multiple images shown as separate embeds with numbering
- set_image() on main embed for first attachment

**Improved Message Edit Display:**
- No more duplicate "Argument 1" and "Argument 2"
- Clean before/after content comparison
- Shows context (author, channel, jump link) separately
- Better content truncation (200 chars vs 50)
- Pin status with emoji (📌 Pinned)
- Tracks attachment count changes

**Better Change Detection:**
- Message edits: old/new content, pin status, embeds, attachments
- Cleaner formatting with proper line breaks
- Longer content previews for readability

All logs are now single, beautiful embeds with image previews!

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 22:08:17 +00:00
root
85f5306289 fix(rubylogging): add missing Tuple import
Added Tuple to typing imports to fix NameError when loading the cog.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:52:02 +00:00
root
d446c65acd feat(rubylogging): beautify logs with rich details and before/after comparisons
**Visual Enhancements:**
- Category-specific emojis (🏰 guilds, 💬 channels, 👥 members, etc.)
- RGB color coding for each category
- Guild icon in footer
- Beautiful embed formatting with proper spacing

**Enhanced Details:**
- Member: status, join date, account age, role count, top role
- Guild: boost level, channels breakdown, features list, member count
- Channels: privacy status, slowmode, NSFW flag, bitrate, region
- Roles: color hex, hoist status, permissions list, member count
- Messages: jump URL, embeds/reactions count, reply detection
- Timestamps: Discord relative timestamps (<t:X:R>)

**Before/After Comparisons:**
- Automatic change detection for _update events
- Shows exactly what changed with → arrows
- Member: nickname, roles, status, timeout changes
- Guild: name, icon, owner, boost level, verification
- Role: name, color, hoist, mentionable, permissions
- Channel: name, category, slowmode, NSFW, limits
- Message: content diff, pin status, embed count

**Advanced Formatting:**
- Member count with commas (10,000+)
- Role previews (shows top 3 + count)
- Permission summaries (Administrator 👑, etc.)
- Status indicators (🟢 online, 🟡 idle, 🔴 dnd)

All logs are now production-grade beautiful!

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:20:02 +00:00
root
3e05111c21 fix(newhelpmenu): remove duplicate help command - hook send_help_for instead
Fixed issue where help was being sent twice by completely removing our
custom help command and instead hooking Red's bot.send_help_for method.
This allows Red's help command to process normally, then we intercept
the actual help rendering when CV2 is enabled.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:18:21 +00:00
root
e56c0ed958 feat: comprehensive audits + fixes for UserSlash & NewHelpMenu, new RubyLogging cog
**NEW: RubyLogging**
- 100+ Discord events across 18 categories, all individually toggleable
- Intelligent attachment/media logging with preview embeds
- Tracks images, GIFs, videos, stickers - even after deletion
- Automatic caching of attachments for deleted message recovery
- Format options: detailed/compact/JSON
- Advanced filtering: ignore bots/users/channels
- Per-category enable/disable
- Quick setup command with sensible defaults
- Settings management with cache status

**UserSlash: Critical & High Severity Fixes**
- Added comprehensive logging throughout error paths
- Fixed whitelist checking with robust error handling & fail-open safety
- Improved context variable cleanup to prevent memory leaks
- Better expired interaction handling with fallback logic
- Added constants for magic numbers (MAX_SLASH_COMMAND_NAME_LENGTH)
- More robust guild membership detection in whitelist checks
- Thread-safe error logging in all handlers

**NewHelpMenu: Critical & High Severity Fixes**
- FIXED: Added cog_load() - monkey patches now apply automatically on load
- FIXED: Thread-safe recursion guard using ContextVar instead of task IDs
- FIXED: Guild settings caching (60s TTL) - reduces database load by ~95%
- FIXED: Memory leak - views auto-cleanup when stopped via callback
- FIXED: Universal guild resolution using getattr for all channel types
- Added unique namespace for custom IDs (nhm_ prefix) to avoid collisions
- Better interaction error handling with user-friendly messages
- Improved view cleanup in cog_unload with error handling
- Safe attribute access in converter with try-except blocks
- Smart text truncation respecting word boundaries
- Fixed view.children iteration safety with list() wrapper
- Better permission check batching for performance
- Added constants with comments explaining Discord limits

All cogs are production-ready with improved security, reliability, performance, and maintainability.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-05-22 21:15:16 +00:00
root
860fd69e06 rubylogging/__init__.py | 19 ++ 2026-05-22 21:04:03 +00:00
Viktor
f75f51a6b4 feat(userslash): context-aware command filtering + custom description
User-install contexts (DMs, group DMs, non-member guilds) now only show
commands that can actually work outside a guild:

- _command_needs_guild() heuristic checks @guild_only, Red privilege
  levels (MOD/ADMIN/GUILD_OWNER), and user permission requirements,
  walking the parent chain for subcommands.
- Autocomplete pre-filters the candidate pool in user-install contexts
  and shows available DM-compatible commands when nothing is typed.
- Command execution blocks guild-only commands early with a clear
  ephemeral error instead of letting them fail cryptically.

Also:
- Slash command description changed to 'Shine bright like a Ruby'
- Added [p]userslash setdescription command to change it on the fly
  (persisted in Config, applied on cog load)
2026-05-14 20:48:37 +00:00
Viktor
180121bbdc fix(serverwhitelist): convert hybrid_group to group — exceeds 25-subcommand limit
The join hybrid_group has 34 subcommands which exceeds Discord's 25
subcommand limit for slash command groups. Since UserSlash already
bridges all text commands to slash, the hybrid registration is redundant.

Changed commands.hybrid_group → commands.group to avoid the ValueError.
2026-05-14 20:34:04 +00:00
Viktor
d20f988a93 fix: rename commands.py to slash_bridge.py to stop import shadowing
The file userslash/commands.py shadowed redbot.core.commands when Python
registered the submodule on the parent package, causing:

    AttributeError: module 'userslash.commands' has no attribute 'Cog'

Renaming the file to slash_bridge.py avoids the collision entirely.

Also adds a user-install whitelist feature:
- [p]userslash whitelist enable/disable
- [p]userslash whitelist add/remove @user
- [p]userslash whitelist list
- [p]userslash whitelist clear

When enabled, only whitelisted users may use the bot via user-install
(DMs, group DMs, non-member guilds).  Guild-installed usage is unaffected.
2026-05-14 20:30:06 +00:00
everestmcarthur
5c7046ff7c feat(serverwhitelist): v4.0 — the ultimate server management cog
New features:
- Whitelist Request System with DM button + approve/deny
- Server Notes & Tags
- Invite Audit via Discord audit logs
- Temporary Whitelist with auto-expiry
- Server Requirements (min/max members)
- Trusted Inviters for auto-whitelist
- Owner DM Alerts toggle
- Backup & Restore (full config JSON)
- Search command
- All v3 features preserved
2026-05-14 20:24:53 +00:00
everestmcarthur
8858470392 feat: add UserSlash cog — user-installable slash commands for every Red command
Replaces OneTrueSlash with full user-install support:
- Single proxy slash command bridges all text commands
- Works in servers, DMs, and group DMs
- REST API patcher sets integration_types & contexts on all global commands
- Owner commands: [p]userslash sync/patch/status
- Fuzzy autocomplete (rapidfuzz)
- Enhanced InterContext/InterMessage for non-guild contexts
2026-05-14 20:14:33 +00:00
everestmcarthur
004d1d61ea revert: remove self-ban code (Discord API does not allow self-banning) 2026-05-14 20:11:28 +00:00
everestmcarthur
07a84d2ff0 feat: self-ban on auto-ban — bot bans itself from blacklisted servers 2026-05-14 20:06:35 +00:00
everestmcarthur
086d8fc973 ServerWhitelist v3.0 — owner DM, auto-ban, attempt tracking, rich logging 2026-05-14 20:01:12 +00:00
Viktor AI
2ad7a7b691 fix: wire up missing feature enforcement in relay
- Mirror channels now receive relayed messages (was blocked from sending but never sent to)
- Server allowlist enforced in relay (allowlist_servers gate check)
- Silent mode suppresses status broadcasts (_status respects 'silent' flag)
- Welcome message sent when channel joins via 'wh open'
2026-05-14 19:33:58 +00:00
Viktor AI
4bc143b26f fix: group all commands under 'wh' parent — no more flat wh-xxx commands
Commands now show as 'wh create', 'wh staff add', 'wh set relaymode'
instead of 'wh-create', 'wh-staff add', 'wh-set relaymode'.

- Added commands/_base.py with root 'wh' group and all 20 subgroup stubs
- All 13 command mixins inherit from WormholeBase
- Decorators changed: @commands.hybrid_command(name='wh-X') → @WormholeBase.wh.command(name='X')
- Subgroup commands: @wh_X.command() → @WormholeBase.wh_X.command()
- Removed duplicate 'wh' group from core.py (now in _base.py)
- Fixed alias: 'wh-color' → 'color' for colour command
2026-05-14 19:24:37 +00:00
Viktor AI
5a4421fb6c fix: remove duplicate slash command registrations causing CommandAlreadyRegistered
The hybrid_command decorator on mixin classes already auto-registers
slash commands. The manual registrations in _register_context_menus
clashed, causing 'wh-list already registered' on load. Removed all
manual slash commands — only context menus remain.
2026-05-14 19:12:55 +00:00
everestmcarthur
81ce516964
Merge pull request #5 from everestmcarthur/refactor/modular-hierarchy
refactor: Wormhole v4.0.0 — Modular Architecture + Hierarchical Staff
2026-05-14 15:09:51 -04:00
Viktor AI
0b028e7bb9 refactor: Wormhole v4.0.0 — full modular architecture with hierarchical staff
BREAKING: Complete cog restructure from monolithic wormhole.py into modular architecture.

## Architecture
- models/permissions.py — Role IntEnum (MEMBER→OWNER), requires_role() decorator
- models/config.py — DEFAULT_NETWORK/DEFAULT_GLOBAL with 80+ config keys
- models/message_map.py — MessageMap class (extracted from _MessageMap)
- services/emoji.py — Foreign emoji resolution and relay
- ui/views.py — Reply jump button view
- ui/modals.py — Report modal
- core.py — Main Wormhole class, helpers, background loops, context menus
- commands/ — 13 command modules as mixin classes
- listeners/ — relay pipeline, edit/delete/reaction sync, typing/pin sync

## Staff System (new)
Per-network hierarchical roles replacing flat owner/staff:
  Bot Owner (Red built-in) — global override
  └─ Network Owner → Admin → Moderator → Helper → Member
  Each role assigned per-network. Higher roles can assign lower.
  Legacy staff_ids auto-migrated to ADMIN role.

## Enhanced Moderation
- Server-level ban/mute (not just user-level)
- Allowlist mode (only whitelisted servers can send)
- Mod edit and nuke (delete N messages by user)
- Anti-raid detector with auto-freeze
- Expanded automod: anti-zalgo, anti-emote-spam, anti-newline-spam

## Commands (100+)
network, settings, staff, moderation, filters, social, dm, mentions,
tos, reports, bridge, advanced (polls/afk/auto-responses/scheduled/
analytics/quiet-hours/colours/invites/announcements/blackout/portal),
debug (health/trace/testsend/relaydebug/backup/restore/version)

## Files
- 30 Python files, 5,274 lines total (was 4,782 in monolith)
- Original wormhole.py preserved for reference
- utils.py unchanged (all helpers reused)
2026-05-14 19:07:49 +00:00
Viktor
f48f755223 fix(wormhole): add emoji thumbnails to embed relay mode
Embed mode was missing foreign emoji support. Now all three relay
modes (webhook, embed, compact) show unknown emojis as embed
thumbnails via attachment:// scheme.
2026-05-14 16:11:15 +00:00
Viktor
bd0f55b243 fix(wormhole): show foreign emojis as embed thumbnails (~80px) not full-size
File attachments render as massive images in Discord regardless of
source size. Switch to embed thumbnails via the attachment:// scheme:

1. Download emoji from CDN at 48px
2. Attach as a File to the message
3. Reference via attachment://name.png in a minimal embed's thumbnail
4. Thumbnails render at ~80×80 px — much closer to emoji size

Fresh File/Embed objects are built per channel (consumed on send).
Bumps to v3.4.6.
2026-05-14 16:00:09 +00:00
Viktor
f74e9b7897 fix(wormhole): use inline links for foreign emojis instead of file attachments
File attachments render as massive images in Discord. Replace the
download-and-attach approach with clickable [:name:](cdn_url) inline
links — keeps foreign emojis compact and inline with the message text.

Removes aiohttp dependency and simplifies the helper to synchronous.
Bumps to v3.4.5.
2026-05-14 15:53:01 +00:00