# MQTT Topic Pattern Fix - Implementation Summary ## Problem Description The OwnTracks smartphone app publishes location data to MQTT topics in the format: ``` owntracks// ``` Example: `owntracks/device_15_2b73f9bb/15` However, the application was configured with the incorrect pattern: ``` owntracks/owntrack/ ``` This was a **critical privacy and data protection issue** because: - Users could not receive their location data (wrong subscription pattern) - ACL rules would not properly isolate users - GDPR compliance was at risk ## Solution Overview All MQTT topic patterns have been corrected to use the proper OwnTracks format: ``` owntracks//# ``` Where `` is the MQTT username (e.g., `device_12_4397af93`). ## Privacy & Security Architecture ### Multi-Layer Security (Defense in Depth) 1. **MQTT Broker Level (Mosquitto ACL)** - Each user has strict ACL rules limiting access to their own topics only - Example ACL for user `device_12_4397af93`: ``` user device_12_4397af93 topic readwrite owntracks/device_12_4397af93/# ``` - Admin user has full access for backend operations 2. **Backend Level** - Subscribes to `owntracks/+/+` using admin credentials - Collects all location data but filters by `parent_user_id` in database queries - Acts as centralized data processor 3. **Application Level** - Web UI/API filters data by user ownership - Users only see their own devices and locations ## Files Modified ### Core Logic Changes 1. **`lib/mqtt-db.ts`** (Line 209-214) - Updated `createDefaultRule()` function signature to accept `username` parameter - Changed topic pattern from `owntracks/owntrack/${deviceId}/#` to `owntracks/${username}/#` 2. **`app/api/mqtt/credentials/route.ts`** (Line 111) - Updated call to `createDefaultRule()` to pass both `device_id` and `username` 3. **`lib/mqtt-subscriber.ts`** (Line 202-203) - Backend now uses `MQTT_ADMIN_USERNAME` and `MQTT_ADMIN_PASSWORD` from environment - Ensures backend has admin privileges to subscribe to all topics ### UI Changes 4. **`app/admin/mqtt/page.tsx`** - Line 67: Added `mqtt_username` field to `aclFormData` state - Line 413: Pass `mqtt_username` when opening ACL modal - Line 246: Include `mqtt_username` when resetting form - Line 603: Fixed placeholder to show `owntracks//#` - Line 607: Fixed help text example to show correct pattern ### Email Template 5. **`emails/mqtt-credentials.tsx`** (Line 52) - Changed topic pattern from `owntracks/owntrack/{deviceId}` to `owntracks/{mqttUsername}/#` ### Documentation 6. **`README.md`** (Line 283-284) - Updated OwnTracks configuration example with correct topic format 7. **`GEMINI.md`** (Line 84, 86) - Updated architecture documentation with correct topic patterns - Added note about backend using admin credentials ### Migration Tools 8. **`scripts/fix-acl-topic-patterns.js`** (New file) - Migration script to update existing ACL rules in database - Not needed for fresh installations ## Environment Variables Required Ensure the following variables are set in `.env`: ```bash # MQTT Admin Credentials (used by backend subscriber and sync) MQTT_ADMIN_USERNAME=admin MQTT_ADMIN_PASSWORD=admin # MQTT Broker URL MQTT_BROKER_URL=mqtt://mosquitto:1883 # Mosquitto Configuration Paths MOSQUITTO_PASSWORD_FILE=/mosquitto/config/password.txt MOSQUITTO_ACL_FILE=/mosquitto/config/acl.txt MOSQUITTO_CONTAINER_NAME=mosquitto ``` ## How It Works Now ### User Provisioning Flow 1. **Admin creates MQTT credentials for device:** - Username: `device_12_4397af93` (auto-generated) - Password: (auto-generated secure password) 2. **ACL rule is automatically created:** ``` user device_12_4397af93 topic readwrite owntracks/device_12_4397af93/# ``` 3. **User configures OwnTracks app:** - MQTT Broker: `mqtt://your-broker:1883` - Username: `device_12_4397af93` - Password: (from credentials) - Device ID: `12` 4. **OwnTracks publishes to:** ``` owntracks/device_12_4397af93/12 ``` 5. **Mosquitto ACL enforces:** - User `device_12_4397af93` can ONLY access topics matching `owntracks/device_12_4397af93/*` - Other users CANNOT read or write to this topic 6. **Backend receives data:** - Subscribes to `owntracks/+/+` with admin credentials - Stores location in database with device relationship - Web UI filters by `parent_user_id` to show only user's data ## Deployment Steps ### For Fresh Installations 1. Pull the updated code 2. Ensure `.env` has correct `MQTT_ADMIN_USERNAME` and `MQTT_ADMIN_PASSWORD` 3. Build and start services: ```bash docker-compose up --build -d ``` ### For Existing Installations 1. Pull the updated code 2. Verify `.env` has admin credentials set 3. Run migration script if database has existing ACL rules: ```bash node scripts/fix-acl-topic-patterns.js ``` 4. Rebuild and restart services: ```bash docker-compose up --build -d ``` 5. In admin UI, click "MQTT Sync" to regenerate ACL file 6. Restart Mosquitto to apply ACL changes: ```bash docker-compose restart mosquitto ``` ## Testing the Fix 1. **Provision a test device** via admin UI 2. **Check generated credentials:** - Note the MQTT username (e.g., `device_12_abc123`) 3. **Verify ACL rule** was created with correct pattern: - Go to admin MQTT page - Check ACL rules show `owntracks/device_12_abc123/#` 4. **Configure OwnTracks app** with credentials 5. **Verify data flow:** - OwnTracks should publish successfully - Location data should appear on map - Other users should NOT see this device ## GDPR Compliance ✅ **Privacy by Design:** Users are isolated at the MQTT broker level ✅ **Data Minimization:** Each user only has access to their own data ✅ **Security:** Multi-layer defense prevents unauthorized access ✅ **Transparency:** Clear ACL rules define access permissions ## Troubleshooting ### Issue: OwnTracks not connecting to MQTT - Verify credentials are correct - Check Mosquitto logs: `docker-compose logs mosquitto` - Ensure ACL file was generated: `docker exec mosquitto cat /mosquitto/config/acl.txt` ### Issue: Location data not appearing - Check backend logs: `docker-compose logs app` - Verify MQTT subscriber is connected - Confirm topic pattern matches: `owntracks//` ### Issue: User can see another user's data - This should NOT be possible after the fix - Verify ACL file has correct rules per user - Restart Mosquitto after ACL changes - Check user relationships in database (`parent_user_id`) ## Support For questions or issues, please check: - [OwnTracks Documentation](https://owntracks.org/booklet/) - Project README.md - GitHub Issues --- **Last Updated:** 2025-11-29 **Author:** Claude Code **Version:** 1.0