A cross-platform desktop client (Windows / Linux / macOS ARM) for bulk automation of iRedAdmin. Built with Dioxus desktop (no Node/JS toolchain), with an embedded browser for authentication and a native panel for bulk operations.
Українська: README.uk.md · Website: netreondev.github.io/MailGrit
cargo build --release -p mailgrit-app-desktop
# → target/release/mailgrit-app-desktop[.exe]On first launch a mailgrit-data/ folder is created next to the binary,
holding all application files.
⚠️ Authorized use only. MailGrit performs bulk create/edit/delete on an iRedAdmin server. Use it only on systems and accounts you own or are authorized to administer. Unauthorized use is illegal and is your sole responsibility. See DISCLAIMER.md.
- Launch
mailgrit-app-desktop. Enter the iRedAdmin URL (e.g.https://mail.example.com/iredadmin) and press Open login form. An application window with the real iRedAdmin form opens. - Sign in to iRedAdmin — you do not need to press anything else: the app detects the login automatically (a hybrid predicate — see How authentication works) and switches to the operations panel on its own.
- Load a CSV (
domain,username,password,display_name,quota_mb). - Run bulk create / edit / delete.
Only one mode is supported — OSE (forms): bulk operations run as a JS fetch
POST of the standard iRedAdmin create/edit HTML form, with a CSRF token. Form
fields:
csrf_token, domainName, username, newpw, confirmpw, cn, preferredLanguage, mailQuota, submit_add_user.
Requests go through the embedded browser webview with a legitimate session, so the mode works behind FortiWeb/WAF too.
Frameless UI: a custom titlebar with the wordmark and window buttons, dark/light
themes with a toggle (saved to config.toml), a symmetric card grid, modal
confirmation for destructive operations, and progress indicators. All components
are a home-grown design system on CSS tokens (no Node/JS toolchain).
The Form diagnostics button performs a GET of the user-creation page and returns the form HTML (field names, action URL, CSRF), shown in the UI and log.
The full operation dump logs, for every operation: request URL/method/ Content-Type, all form fields (with password/CSRF/email/PII masked), CSRF value and GET-form status, HTTP response status/headers, the full server response body (up to 5000 chars), and the success/error markers plus post-verification result.
The login is detected data-driven, by the login webview navigating to
/dashboard — not by cookie-name guessing. iRedAdmin, Django, and FortiWeb all
use different cookie names, so guessing is brittle; behind a WAF the backend
session is held by the proxy, and replaying a cookie in a separate HTTP client
does not authenticate against the backend. Therefore operations are executed as
JS fetch() inside the same webview that holds the legitimate session.
- Encrypted hash-chained audit log — every operation is appended to a tamper-evident chain (HMAC-SHA256), encrypted at rest with streaming AEAD (XChaCha20-Poly1305).
- Master password — derives the audit-log key and the export-encryption key via Argon2id (memory-hard KDF). The password is never stored; if lost, the audit log and encrypted exports cannot be unlocked.
unsafe_code = "forbid"at the workspace level — nounsafeanywhere in the application crates (wry 0.53 returns HttpOnly cookies natively).
domain,username,password,display_name,quota_mb
example.com,john,S3cret!,John Doe,512
- BOM is stripped automatically; encoding must be UTF-8.
- Flexible column mapping: header names are matched case-insensitively against canonical fields, so localized or renamed headers still map.
- Hard limits (rows, line length, field length) protect against accidental huge
inputs; see
core-domainlimit constants.
The UI ships in 9 languages:
| Code | Language | Endonym |
|---|---|---|
| en | English | English |
| de | German | Deutsch |
| fr | French | Français |
| es | Spanish | Español |
| it | Italian | Italiano |
| pt | Portuguese | Português |
| nl | Dutch | Nederlands |
| pl | Polish | Polski |
| uk | Ukrainian | Українська |
Translations are embedded into the binary at compile time (rust-i18n); the
selected language is persisted in config.toml.
A Cargo workspace of five crates, each compiling/testing in isolation
(cargo test -p <crate>):
| Crate | Responsibility |
|---|---|
core-domain |
Domain types (Newtype/Typestate), domain errors, limit constants, password policy |
core-csv |
CSV parsing & validation with BOM stripping and hard memory limits |
core-storage |
Local SQLite storage: operation log, hash-chained audit log |
core-security |
At-rest crypto: streaming AEAD, HMAC hash-chain, Argon2id KDF |
app-desktop |
Dioxus 0.7 desktop app: login window, cookie handling, native RSX panel |
core-domain ─┬─ core-csv ────┐
├─ core-storage ─┤
└─ core-security ┴─ app-desktop
| Task | Command |
|---|---|
| Format | cargo fmt --all (check: cargo fmt --all -- --check) |
| Lint | cargo clippy --workspace --all-targets --all-features -- -D warnings |
| Tests | cargo nextest run --workspace |
| Doc tests | cargo test --workspace --doc |
| Release build | cargo build --release -p mailgrit-app-desktop |
| Run with debug log | $env:RUST_LOG="debug"; .\target\release\mailgrit-app-desktop.exe |
| Supply chain | cargo deny check advisories bans licenses sources then cargo audit |
| Unused deps | cargo machete --skip-target-dir |
| SemVer | cargo semver-checks --workspace |
The workspace enforces a strict, declarative lint policy in Cargo.toml:
panic, unwrap_used, expect_used, indexing_slicing,
arithmetic_side_effects, todo/unimplemented/unreachable, dbg_macro,
and print_stdout/print_stderr are all deny; unsafe_code is forbid.
All clippy groups (correctness, suspicious, complexity, perf,
pedantic, nursery, cargo) are deny. The only documented exception is
doc_markdown = "allow" (false-positives on technical acronyms).
Rust 1.97.1, pinned via rust-toolchain.toml (edition 2024).
| Platform | Target |
|---|---|
| Windows | x86_64-pc-windows-msvc |
| Linux | x86_64-unknown-linux-gnu |
| macOS (Apple Silicon) | aarch64-apple-darwin |
CI runs the full quality gate (fmt, clippy, nextest, doc tests, cargo-deny, cargo-audit, cargo-machete, cargo-semver-checks) on all three, plus a release build matrix. Formal verification (Kani, Miri), mutation testing (cargo-mutants), and continuous fuzzing (cargo-fuzz) run nightly and are non-blocking.
Dual-licensed under MIT OR Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE. Contributions are made under the same dual license (inbound = outbound); see CONTRIBUTING.md.
| Document | Purpose |
|---|---|
| DISCLAIMER.md | Authorized-use policy, no-warranty, and limitation of liability |
| PRIVACY.md | Data handling — local-only storage, PII masking, no telemetry |
| SECURITY.md | Vulnerability reporting and security posture |
| NOTICE.md | Copyright, licensing, and trademark attribution |
Trademarks: "iRedAdmin" is a trademark of its respective owners. MailGrit is not affiliated with, endorsed by, or sponsored by iRedAdmin or its developers; the name is used solely to indicate compatibility. See NOTICE.md.
MailGrit is free and open source. If it saves you time, consider supporting its development: