Privacy-preserving push notification server for Mostro P2P trades. Inspired by MIP-05, this server enables targeted push notifications without exposing user data to Firebase/Apple.
┌─────────────────┐ 1. Register token ┌──────────────────┐
│ Mostro Mobile │ ─────────────────────────► │ Push Server │
│ │ (encrypted) │ │
│ trade_pubkey │ │ Stores: │
│ + FCM token │ │ trade_pubkey → │
└─────────────────┘ │ device_token │
└────────┬─────────┘
│
┌─────────────────┐ 2. Publishes event ┌────────▼─────────┐
│ Mostro Daemon │ ─────────────────────────► │ Nostr Relay │
│ │ kind 1059 │ │
│ (no changes │ p: trade_pubkey │ │
│ required) │ └────────┬─────────┘
└─────────────────┘ │
│ 3. Server observes
┌────────▼─────────┐
│ Push Server │
│ │
│ Extracts p tag │
│ Looks up token │
│ Sends push │
└────────┬─────────┘
│
┌────────▼─────────┐
│ FCM / APNs │
│ (silent push) │
└────────┬─────────┘
│
┌────────▼─────────┐
│ Mostro Mobile │
│ wakes up, │
│ fetches events │
└──────────────────┘
- Server knows: Temporary mapping of
trade_pubkey→device_token, timing of events - Server does NOT know: User identity (npub), message content, which orders belong to whom
- Firebase/Apple know: A notification occurred (unavoidable with push)
- Firebase/Apple do NOT know: Nostr identity, trade details, message content
- Targeted notifications: Only the recipient device receives the push (not broadcast)
- Encrypted token registration: Device tokens are encrypted with server's public key
- Privacy-first: No persistent storage, tokens auto-expire
- Firebase Cloud Messaging (FCM) support
- UnifiedPush support (GrapheneOS, LineageOS)
- Automatic relay reconnection
- HTTP API for token management
- Rust 1.75 or higher
- Access to a Nostr relay
- (Optional) Firebase account with service account for FCM
git clone <repository-url>
cd mostro-push-servercp .env.example .env
nano .envEdit the .env file with your configurations:
NOSTR_RELAYS=wss://relay.mostro.network
SERVER_HOST=0.0.0.0
SERVER_PORT=8080
FCM_ENABLED=true
UNIFIEDPUSH_ENABLED=true
FIREBASE_PROJECT_ID=your-project
RUST_LOG=infocargo runcargo build --release
./target/release/mostro-push-backenddocker build -t mostro-push-backend .docker-compose up -dcurl http://localhost:8080/api/healthResponse:
{"status":"ok"}Get the server's public key (needed by clients to encrypt tokens):
curl http://localhost:8080/api/infoResponse:
{
"server_pubkey": "02abc123...",
"version": "0.2.0",
"encrypted_token_size": 281
}curl http://localhost:8080/api/statusResponse:
{
"status": "running",
"version": "0.2.0",
"server_pubkey": "02abc123...",
"tokens": {
"total": 42,
"android": 35,
"ios": 7
}
}Register an encrypted device token for a trade. The client must encrypt the token using the server's public key.
curl -X POST http://localhost:8080/api/register \
-H "Content-Type: application/json" \
-d '{
"trade_pubkey": "abc123...def456",
"encrypted_token": "<base64-encoded-encrypted-token>"
}'Response:
{
"success": true,
"message": "Token registered successfully",
"platform": "android"
}curl -X POST http://localhost:8080/api/unregister \
-H "Content-Type: application/json" \
-d '{
"trade_pubkey": "abc123...def456"
}'┌─────────────────┐
│ Nostr Relays │
│ (kind 1059) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Rust Backend │
│ - WebSocket │
│ - Event batch │
│ - HTTP API │
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌─────┐ ┌──────────┐
│ FCM │ │UnifiedPush│
└──┬──┘ └────┬─────┘
│ │
▼ ▼
[Android] [GrapheneOS]
mostro-push-backend/
├── Cargo.toml
├── .env.example
├── src/
│ ├── main.rs # Entry point
│ ├── config.rs # Configuration
│ ├── nostr/
│ │ ├── mod.rs
│ │ └── listener.rs # Nostr event listener
│ ├── push/
│ │ ├── mod.rs # PushService trait
│ │ ├── fcm.rs # FCM implementation
│ │ └── unifiedpush.rs # UnifiedPush implementation
│ ├── api/
│ │ ├── mod.rs
│ │ └── routes.rs # HTTP endpoints
│ └── utils/
│ ├── mod.rs
│ └── batching.rs # Batching management
├── Dockerfile
├── docker-compose.yml
└── README.md
To use FCM, you need:
- Create a project in Firebase Console
- Download the service account JSON file
- Configure the environment variables:
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_SERVICE_ACCOUNT_PATH=/path/to/service-account.json
FCM_ENABLED=trueThe backend logs detailed information that you can monitor:
# Production logs
tail -f /var/log/mostro-push-backend/app.log
# Docker logs
docker-compose logs -f push-backendImportant events:
- Connection to Nostr relays
- Receipt of kind 1059 events
- Notification sending
- Connection errors
cargo testcargo clippycargo fmtA test script is provided to verify all endpoints:
# Start the server
RUST_LOG=info cargo run
# In another terminal, run tests
./test_server.shThe test script will:
- Check health endpoint
- Verify status endpoint
- Register a test UnifiedPush endpoint
- Verify persistence (check data/unifiedpush_endpoints.json)
- Unregister the endpoint
- Test the notification system
- Nostr listener with Mostro pubkey filtering (Option B: Silent Push Global)
- UnifiedPush endpoint registration/unregistration
- Persistent storage for UnifiedPush endpoints (JSON file)
- FCM OAuth2 token refresh with JWT signing
- Intelligent notification batching (5s delay, 60s cooldown)
- HTTP API for endpoint management
- Automatic relay reconnection
- Implement retry logic for failed push deliveries
- Add metrics and monitoring (Prometheus)
- Implement authentication for API endpoints
- Support for multiple Mostro instances
- Integration tests with mock Nostr relay
- Docker deployment configuration
See LICENSE file for details.
Contributions are welcome. Please open an issue first to discuss the changes you would like to make.