A unified SMS verification tool built with Rust + Tauri 2.
MaDao is a unified SMS verification tool built with Rust + Tauri 2. It aggregates resources from HeroSms, 5Sim, and SMSBower, lets you configure routing plans by service type, country, and operator, and uses anonymous aggregate statistics to help you find the country and route combinations with the highest success rates — no more guessing.
- Multi-provider SMS activation — acquire phone numbers, poll for OTP codes, and release tickets through a unified interface across multiple upstream providers
- Routing plans — named activation strategies with sequential or random execution, multi-round failover, price filtering, and automatic replace/failover workflows
- Provider manifest system — TOML-based declarative configuration with runtime hot-reload, no code changes needed to onboard a new provider
- Phone number reuse — automatic reuse pool with configurable TTL, max reuse count, and same-activation retry for cost optimization
- Real-time dashboard — live ticket status, provider balance, recent activity, and runtime logs in a single console
- Callback integration — register webhook URLs per ticket; daemon pushes verification codes to your system automatically
- Anonymous usage statistics — opt-in aggregated stats via Cloudflare Worker + D1, with public summary snapshots
- Desktop + Docker + API — run as a native desktop app (macOS / Linux / Windows), a Docker web console, or integrate directly via HTTP API
- Auto-update — built-in Tauri updater with signed releases from GitHub
- i18n — UI supports English and Chinese with runtime language switching
| Overview | Providers |
|---|---|
| Routing | Stats Dashboard |
|---|---|
- Layered Rust workspace —
plugin-sdk,sms-core,sms-server,apps/daemon,src-tauri - Tauri 2 desktop shell with React 19 frontend
- Multi-protocol support —
handler_api,five_sim, localmock - Extensible manifests —
ui,behavior, and profile-driven extension points
.
├── apps/daemon/ # Local HTTP / Unix socket daemon entry
├── cloudflare/
│ └── stats-worker/ # Cloudflare Worker + D1 for stats aggregation
├── crates/
│ ├── plugin-sdk/ # Provider manifest and protocol config models
│ ├── sms-core/ # Domain models, provider trait, service layer
│ └── sms-server/ # Axum HTTP API layer
├── config/server.toml # Base daemon configuration
├── plugins/providers/ # Default provider manifest templates
├── src-tauri/ # Tauri 2 desktop host
├── ui/ # React + Vite frontend
└── docs/ # Architecture, provider, release, and dev docs
- Rust / Cargo (stable)
- Node.js + npm
- Docker / Docker Compose (optional, for web deployment)
npm run build # Build the frontend
cargo check --workspace # Verify Rust workspace
cargo run -p madao-sms-daemon # Start the daemon
cargo run -p madao-tauri # Launch the Tauri desktop shellcp .env.docker.example .env
docker compose up -d --buildOpen http://127.0.0.1:8080 after startup. For operations, upgrades, and troubleshooting, see Docker Deployment.
To use prebuilt Docker Hub images instead of local builds:
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -dPublished images support linux/amd64 and linux/arm64.
The cloudflare/stats-worker/ directory contains a Cloudflare Worker + D1 service for anonymous usage statistics aggregation.
When stats sync is enabled in Settings, the app uploads ticket outcome events approximately once per minute. The Settings screen provides a manual Sync now action for pending events. Public summaries use precomputed snapshots — newly uploaded events appear after the Worker cron runs or the admin refresh endpoint is called.
cd cloudflare/stats-worker && npm install
npx wrangler login
npx wrangler d1 create madao-statsCopy the returned database_id into wrangler.jsonc and set your API_TOKEN. The schema is auto-created on first request.
npm run dev # Local development
npm run deploy # Deploy to CloudflareSee cloudflare/stats-worker/README.md for details.
The daemon reads its runtime config from the user config directory (not the repository templates):
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/com.madao.sms |
| Linux | $XDG_CONFIG_HOME/com.madao.sms or ~/.config/com.madao.sms |
Repository-side plugins/providers/*.toml files are templates only — do not store real secrets in them.
| Mode | Endpoint |
|---|---|
| HTTP | 0.0.0.0:7822 |
| Unix socket | /tmp/madao-sms.sock |
| Docker Web UI | http://127.0.0.1:8080 |
| Docker backend | daemon:7822 (internal) |
| Docker config dir | /var/lib/madao |
- macOS / Linux desktop: local Unix socket
- Windows desktop: embedded local HTTP API
- Browser / API: HTTP with secret-based authentication
The embedded HTTP service listens on all interfaces. Web console access requires HTTP secret login; protected API routes require an authenticated session. The HTTP secret is stored in runtime-settings.json and can be regenerated but not manually edited in the UI.
In Docker mode, MADAO_HTTP_SECRET can override the persisted secret. Port changes take effect after daemon restart.
npm run build
cargo check --workspace
cargo test -p sms-core
curl http://127.0.0.1:7822/health
curl http://127.0.0.1:7822/api/provider-manifests- 中文文档
- Architecture
- API Integration
- Daemon API Reference
- Provider Compatibility
- Routing Plans
- Development
- OpenAPI / Swagger UI
- Docker Deployment
- Cloudflare Stats Worker
- Release Guide
- Contributing
- Security Policy
- Releases / Changelog
Released under the GNU Affero General Public License v3.0 only.
The MaDao name, logo, release channels, and official project identity are covered by the Trademark Policy. Modified versions must not imply official endorsement or use confusingly similar branding without permission.
- LINUX DO
- Thanks to Maestro-Flow for its workflow ideas and tooling inspiration.
- Thanks to FlowPilot for its workflow ideas and tooling inspiration.