A secure, robust LINE Bot service for remotely controlling a garage door via the LINE messaging platform. Authenticated users can open and close the garage door only after verifying they are physically present at the configured location.
- Features
- System Architecture
- Security Features
- Project Structure
- Prerequisites
- Installation
- Configuration
- User Management
- MQTT Integration
- API Documentation
- Logging
- Testing
- Contributing
- License
- Changelog
- User Authentication: Only registered users in the SQLite database can control the garage door.
- Geolocation Verification: Users must be physically present near the garage (configurable radius) to operate the door.
- One-Time Token System: Secure, single-use tokens prevent replay attacks.
- TLS-Encrypted MQTT Communication: Securely communicates with the garage door controller over MQTT.
- Certificate Validation: Verifies broker certificates against a trusted CA.
- Redis Cache (Optional): Distributed token storage with in-memory fallback.
- HMAC Signature Validation: Verifies all LINE webhook requests.
- Rate Limiting: IP-based rate limits protect against abuse.
- Security Headers: Implements HSTS, XSS protection, Content-Security-Policy, and other headers.
- Detailed Logging: Console logging with configurable levels; file-based logging to
/tmp
. - Swagger/OpenAPI Docs: Interactive API documentation served under
/api/docs
. - Static Verification Page: Browser-based geolocation capture at
/static/verify.html
.
- LINE Webhook Handler (
/webhook
): Receives messages via LINE Messaging API. - Location Verification (
/verify-location
): Browser geolocation API posts coordinates for proximity check. - Token Manager: Generates, stores, and validates single-use tokens.
- MQTT Client: Publishes open/close commands to the garage controller.
- Redis Cache: Optional backend for token and rate-limit state.
- Static Pages: Served from the
static/
directory (verification page).
- HMAC-SHA256 signature validation of incoming LINE requests.
- Single-use tokens with configurable TTL.
- Geofence enforcement using the haversine formula.
- TLS encryption for all HTTP and MQTT traffic.
- Certificate Authority verification of MQTT broker.
- IP-based rate limiting with configurable thresholds.
- Security-focused HTTP headers on all responses.
/linebot.test/
├── app.py # Main Flask application
├── app.yaml # App Engine configuration
├── requirements.txt # Python dependencies
├── static/ # Static files (verify.html)
├── core/
│ ├── line_webhook.py # LINE webhook logic
│ ├── token_manager.py # Token generation & validation
│ └── mqtt_handler.py # MQTT publish logic
├── middleware/
│ ├── rate_limiter.py # Request rate limiting
│ └── security.py # Signature & header middleware
├── utils/
│ ├── logger_config.py # Logging setup
│ └── createUserDatabase.py / insertUsertoDatabase.py
├── docs/
│ └── api_docs.py # Swagger/OpenAPI generator
└── tests/ # pytest test suite
├── test_app.py
├── test_line_webhook.py
├── test_mqtt_handler.py
└── test_token_manager.py
- Python 3.9+
- Google Cloud SDK (for App Engine deployment)
- A LINE Developer account and Messaging API channel
- An MQTT broker (EMQX Cloud, HiveMQ, etc.)
- Redis server (optional; falls back to in-memory)
- CA certificate for MQTT broker (if not publicly trusted)
- OS packages:
mosquitto-clients
(for local MQTT testing) - Copy
.env.example
to.env
and fill in your credentials
- Clone the repo and install dependencies.
- Copy and configure
.env
from.env.example
. - Run
python app.py
(or deploy to App Engine).
git clone https://github.com/brian13579/linebot.test.git
cd linebot.test
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# edit .env with your credentials and settings
python app.py
Visit http://localhost:8080/static/verify.html?token=TEST
and test /webhook
via curl
.
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
gcloud app create --region=YOUR_REGION
gcloud app deploy app.yaml
Update your LINE webhook to https://YOUR_PROJECT_ID.appspot.com/webhook
.
Create a .env.example
with:
LINE_CHANNEL_ACCESS_TOKEN=your_access_token
LINE_CHANNEL_SECRET=your_channel_secret
MQTT_BROKER=mqtt.example.com
MQTT_PORT=8883
MQTT_USERNAME=your_user
MQTT_PASSWORD=your_pass
MQTT_TOPIC=garage/command
Environment variables (set in .env
or app.yaml
):
LINE_CHANNEL_ACCESS_TOKEN=
LINE_CHANNEL_SECRET=
MQTT_BROKER=
MQTT_PORT=8883
MQTT_USERNAME=
MQTT_PASSWORD=
MQTT_TOPIC=garage/command
MQTT_CAFILE=ca.crt
PARK_LAT=24.79155
PARK_LNG=120.99442
MAX_DIST_KM=0.5
VERIFY_URL_BASE=https://YOUR_DOMAIN/static/verify.html
REDIS_URL=redis://:password@host:6379/0
CACHE_ENABLED=false
RATE_LIMIT_ENABLED=true
MAX_REQUESTS_PER_MINUTE=30
- Initialize SQLite DB:
python utils/createUserDatabase.py
- Add users:
python utils/insertUsertoDatabase.py
Your bot publishes messages to the configured MQTT topic:
client.publish(os.environ['MQTT_TOPIC'], payload='open')
Ensure your controller subscribes to the same topic.
Available at /api/docs
when the app is running; serves interactive Swagger UI.
- Console: All logs printed to stdout (captured by Stackdriver).
- File: Logs at level INFO+ written to
/tmp/app.log
. - Error: ERROR+ logs to
/tmp/error.log
.
Run tests with coverage:
pytest --cov=. tests/
- SSL Hostname Mismatch: Regenerate your MQTT broker cert with the correct SAN.
- 502 Bad Gateway on App Engine: Ensure
/healthz
exists andscript: auto
is configured inapp.yaml
. - Permission Denied on Cloud Build: Grant
roles/cloudbuild.builds.editor
to the Cloud Build service account.
- Fork the repo
- Create a feature branch
- Commit changes
- Submit a Pull Request
MIT License. See LICENSE for details.
For questions or issues, please open an issue on the GitHub repo or reach out via email: [email protected]