A sophisticated Flask-based web application that aggregates, analyzes, and monitors aviation news from multiple RSS/Atom feeds and web sources. Features real-time sentiment analysis, AI-powered summarization, and intelligent feed management.
- Multi-Source Aggregation: Ingest news from RSS/Atom feeds and HTML pages
- Sentiment Analysis: Automatic sentiment scoring using TextBlob
- AI Summarization: Integration with Cloudflare Workers for AI-powered summaries
- Real-time Updates: Server-Sent Events (SSE) for live notifications
- Auto-refresh: Periodic background feed updates with parallel processing
- Content Deduplication: Hash-based duplicate detection
- Smart Feed Discovery: Automatic RSS/Atom feed detection
- Search & Filter: Full-text search and sentiment filtering
- Data Export: CSV export functionality
- Responsive UI: Dark/light theme support
This version includes comprehensive security enhancements:
- Input Validation: All user inputs are validated and sanitized
- SSRF Protection: URL validation prevents access to private networks
- Rate Limiting: API endpoints have rate limits to prevent abuse
- Security Headers: CSP, HSTS, and other security headers (via Flask-Talisman)
- Centralized Configuration: Environment-based configuration management
- Enhanced Logging: Structured logging with configurable levels
- No Hardcoded Secrets: All sensitive values use environment variables
- Python 3.8 or higher
- pip (Python package manager)
-
Clone the repository
git clone <your-repo-url> cd AviationNews
-
Create a virtual environment (recommended)
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies
pip install -r requirements.txt
-
Configure environment variables
cp .env.example .env
Edit
.envand set your configuration values:- REQUIRED: Change
CF_WORKER_TOKENto a secure random token - REQUIRED: Change
SECRET_KEYto a secure random key - RECOMMENDED: Update
CF_WORKER_URLif you have your own Cloudflare Worker - OPTIONAL: Configure domain restrictions, rate limits, etc.
Generate secure tokens:
# Generate a secret key python -c "import secrets; print(secrets.token_hex(32))" # Generate a worker token python -c "import secrets; print(secrets.token_urlsafe(32))"
- REQUIRED: Change
-
Initialize the database
python app.py
The database will be automatically created on first run.
python app.pyThe application will start on http://localhost:5001 by default.
- Navigate to the main dashboard
- Enter a URL in the "Ingest New Content" field
- Optionally check "Auto-add as feed" to save it for automatic updates
- Click "Ingest"
- View all feeds in the "Manage Feeds" section
- Refresh feeds manually or enable auto-refresh
- Remove feeds you no longer need
- Navigate to the main feed view
- Click "Generate AI Summaries"
- Summaries will be processed in batches and appear in real-time
See .env.example for all available configuration options:
| Variable | Description | Default |
|---|---|---|
AIH_DB |
Database file path | emails.db |
PORT |
Server port | 5001 |
SECRET_KEY |
Flask secret key | Auto-generated |
CF_WORKER_URL |
Cloudflare Worker URL | (required for AI) |
CF_WORKER_TOKEN |
Worker authentication token | (required for AI) |
RATE_LIMIT_ENABLED |
Enable rate limiting | True |
ALLOWED_DOMAINS |
Domain whitelist (comma-separated) | (empty = all allowed) |
BLOCKED_DOMAINS |
Domain blacklist (comma-separated) | See .env.example |
Domain Restrictions (SSRF Protection):
- Set
ALLOWED_DOMAINSto restrict which domains can be fetched BLOCKED_DOMAINSprevents access to private networks (pre-configured)- Private IPs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8) are always blocked
Rate Limiting:
- Default: 60 requests per minute per IP
- Customize with
RATE_LIMIT_DEFAULT(e.g., "100 per minute", "5 per second") - Disable with
RATE_LIMIT_ENABLED=False(not recommended)
GET /- Main dashboardPOST /api/ingest- Ingest a new URLGET /api/emails- Get news items (paginated, filterable)GET /api/news/<id>- Get single news itemGET /api/stats- Get statistics
GET /api/feeds- List all feedsPOST /api/feeds/add- Add a new feedDELETE /api/feeds/<id>- Remove a feedPOST /api/feeds/refresh- Refresh feedsPOST /api/feeds/auto-refresh- Toggle auto-refresh
POST /api/ai/summarize- Generate AI summariesGET /api/ai/updates- SSE stream for real-time updatesGET /api/export- Export data as CSV
Debug mode is enabled by default when running locally:
python app.py-
Set environment variables:
export FLASK_ENV=production export FLASK_DEBUG=False
-
Use a production WSGI server (e.g., Gunicorn):
pip install gunicorn gunicorn -w 4 -b 0.0.0.0:5001 app:app
-
Important: Configure a reverse proxy (nginx, Caddy) with HTTPS
AviationNews/
├── app.py # Main Flask application
├── config.py # Configuration management
├── security.py # Security utilities (validation, SSRF protection)
├── requirements.txt # Python dependencies
├── .env # Environment variables (DO NOT COMMIT!)
├── .env.example # Example environment configuration
├── .gitignore # Git ignore rules
├── templates/ # HTML templates
│ ├── base.html
│ ├── index.html
│ └── ...
└── emails.db # SQLite database (auto-created)
If you encounter database errors, try:
rm emails.db
python app.pyIf the app fails to start with configuration errors:
- Check your
.envfile syntax - Ensure all required variables are set
- Validate numeric values are within acceptable ranges
If you're hitting rate limits during testing:
- Set
RATE_LIMIT_ENABLED=Falsein.env - Or increase limits:
RATE_LIMIT_DEFAULT=1000 per minute
- Never commit
.envoremails.dbto version control - Change default tokens before deploying
- Use HTTPS in production (configure reverse proxy)
- Restrict domains with
ALLOWED_DOMAINSif possible - Keep dependencies updated:
pip install -U -r requirements.txt - Monitor logs for suspicious activity
- Enable rate limiting in production
See SECURITY.md for detailed security information.
[Your License Here]
Contributions are welcome! Please ensure:
- Code follows existing style
- Security best practices are maintained
- Tests are included (when available)
- Documentation is updated
For issues, questions, or contributions, please open an issue on GitHub.