Fix MQTT topic pattern for OwnTracks and implement privacy isolation
CRITICAL FIX: The OwnTracks app publishes to owntracks/<username>/<device_id>, not owntracks/owntrack/<device_id>. This was causing data delivery failures and privacy violations. Changes: - Fix ACL topic pattern: owntracks/<username>/# (was: owntracks/owntrack/<device_id>) - Backend now uses MQTT_ADMIN_USERNAME for global subscription - Update UI forms and placeholders with correct pattern - Update email template with correct topic format - Enable Mosquitto ACL file for user isolation - Add migration script for existing ACL rules - Update documentation (README, GEMINI.md) Privacy & Security: - Each user isolated at MQTT broker level via ACL - Backend subscribes with admin credentials to owntracks/+/+ - Web UI filters data by parent_user_id for additional security - GDPR compliant multi-layer defense in depth Files changed: - lib/mqtt-db.ts - Updated createDefaultRule() to use username - app/api/mqtt/credentials/route.ts - Pass username to ACL creation - app/admin/mqtt/page.tsx - UI forms and state management - emails/mqtt-credentials.tsx - Email template topic pattern - lib/mqtt-subscriber.ts - Use admin credentials from env - mosquitto/config/mosquitto.conf - Enable ACL enforcement - README.md, GEMINI.md - Documentation updates - scripts/fix-acl-topic-patterns.js - Migration script - MQTT_TOPIC_FIX.md - Detailed implementation guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
228
MQTT_TOPIC_FIX.md
Normal file
228
MQTT_TOPIC_FIX.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# MQTT Topic Pattern Fix - Implementation Summary
|
||||
|
||||
## Problem Description
|
||||
|
||||
The OwnTracks smartphone app publishes location data to MQTT topics in the format:
|
||||
```
|
||||
owntracks/<username>/<device_id>
|
||||
```
|
||||
|
||||
Example: `owntracks/device_15_2b73f9bb/15`
|
||||
|
||||
However, the application was configured with the incorrect pattern:
|
||||
```
|
||||
owntracks/owntrack/<device_id>
|
||||
```
|
||||
|
||||
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/<username>/#
|
||||
```
|
||||
|
||||
Where `<username>` 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/<username>/#`
|
||||
- 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/<username>/<device_id>`
|
||||
|
||||
### 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
|
||||
Reference in New Issue
Block a user