fix: allow true server owner to bypass rank check on channel role-permission overrides The set_role_permissions route blocks editing a role's channel permission overrides whenever role.rank <= the acting member's rank (NotElevated), to prevent privilege-escalation loops. However this check has no exemption for the server's true owner (server.owner == user.id). If an owner has assigned themselves their own top-level role (e.g. "Admin"/"Server Admin" - extremely common since most server setups have the owner hold their highest role for visible status/cosmetics), that role's rank is necessarily equal to their own computed member rank, so the check incorrectly throws NotElevated for the owner too - even though server owners by definition outrank every role and every member, owner-held roles included. This produces a confusing experience: the owner cannot edit channel-level overrides for their own top role via the UI, with no clear explanation, and may reasonably believe something is broken or their permissions are miscconfigured (they aren't). This adds a short-circuit: if the acting user is the server's owner, skip the rank comparison entirely, matching how Stoat already treats true ownership as an absolute bypass elsewhere in the permission system (e.g. channel-visibility lockout cascades). Signed-off-by: bluecords <133072610+bluecords@users.noreply.github.com>
Stoat Backend
The services and libraries that power the Stoat service.| Crate | Path | Description | |
|---|---|---|---|
core/config |
crates/core/config | Core: Configuration | |
core/database |
crates/core/database | Core: Database Implementation | |
core/files |
crates/core/files | Core: S3 and encryption subroutines | |
core/models |
crates/core/models | Core: API Models | |
core/permissions |
crates/core/permissions | Core: Permission Logic | |
core/presence |
crates/core/presence | Core: User Presence | |
core/result |
crates/core/result | Core: Result and Error types | |
core/coalesced |
crates/core/coalesced | Core: Coalescion service | |
delta |
crates/delta | REST API server | |
bonfire |
crates/bonfire | WebSocket events server | |
services/january |
crates/services/january | Proxy server | |
services/gifbox |
crates/services/gifbox | Tenor proxy server | |
services/autumn |
crates/services/autumn | File server | |
daemons/crond |
crates/daemons/crond | Timed data clean up daemon server | |
daemons/pushd |
crates/daemons/pushd | Push notification daemon server |
Minimum Supported Rust Version
Rust 1.86.0 or higher.
Development Guide
Before contributing, make yourself familiar with our contribution guidelines and the technical documentation for this project.
Before getting started, you'll want to install:
- mise
- Docker
- Git
- mold (optional, faster compilation)
A default.nix is available for Nix users! Run
nix-shellto activate mise.
As a heads-up, the development environment uses the following ports:
| Service | Port |
|---|---|
| MongoDB | 27017 |
| Redis | 6379 |
| MinIO | 14009 |
| Maildev | 14025 14080 |
| Revolt Web App | 14701 |
| RabbitMQ | 5672 15672 |
crates/delta |
14702 |
crates/bonfire |
14703 |
crates/services/autumn |
14704 |
crates/services/january |
14705 |
crates/services/gifbox |
14706 |
Now you can clone and build the project:
git clone https://github.com/stoatchat/stoatchat stoat-backend
cd stoat-backend
mise install
mise build
Tip
You can override
BUILDERin your.envfile to run cargo with mold if you installed it:# .env BUILDER = "mold --run cargo"
A default configuration Revolt.toml is present in this project that is suited for development.
If you'd like to change anything, create a Revolt.overrides.toml file and specify relevant variables.
Tip
Use Sentry to catch unexpected service errors:
# Revolt.overrides.toml [sentry] api = "https://abc@your.sentry/1" events = "https://abc@your.sentry/1" files = "https://abc@your.sentry/1" proxy = "https://abc@your.sentry/1"
Tip
If you have port conflicts on common services, you can try the following:
# compose.override.yml services: redis: ports: !override - "14079:6379" database: ports: !override - "14017:27017" rabbit: ports: !override - "14072:5672" - "14672:15672"With the corresponding Revolt configuration:
# Revolt.overrides.toml # and Revolt.test-overrides.toml [database] mongodb = "mongodb://127.0.0.1:14017" redis = "redis://127.0.0.1:14079/" [rabbit] port = 14072And mise configuration
#.env DATABASE_PORT = "14017" RABBIT_PORT = "14072" REDIS_PORT = "14079"
Then continue:
cp livekit.example.yml livekit.yml
mise start
You can start a web client by doing the following in another terminal:
# if you do not have yarn yet and have a modern Node.js:
corepack enable
# clone the web client and run it:
git clone --recursive https://github.com/stoatchat/for-web stoat-web
cd stoat-web
# refer to stoat-web/README.md for startup, creating an account and loging in
When signing up, go to http://localhost:14080 to find confirmation/password reset emails.
To stop all services, hit (CTRL + c) in the terminal you ran mise start and run mise docker:stop
Deployment Guide
Cutting new crate releases
Begin by bumping crate versions:
just patch # 0.0.X
just minor # 0.X.0
just major # X.0.0
Then commit the changes to package files.
Proceed to publish all the new crates:
just publish
Cutting new binary releases
Tag and push a new release by running:
just release
If you have bumped the crate versions, proceed to GitHub releases to create a changelog.
Testing
First, start the required services:
docker compose up -d
Now run tests for whichever database:
TEST_DB=REFERENCE cargo nextest run
TEST_DB=MONGODB cargo nextest run
License
The Stoat backend is generally licensed under the GNU Affero General Public License v3.0.
Individual crates may supply their own licenses!