Compare commits

...

1 Commits

Author SHA1 Message Date
Matthew Raymer 5ecde954b7 docs: improve documentation across WebPushService class 1 week ago
  1. 33
      SECURITY_CHECKLIST.md
  2. 845
      app.py
  3. 71
      models.py
  4. 1
      requirements.txt

33
SECURITY_CHECKLIST.md

@ -0,0 +1,33 @@
# Security Audit Checklist for Web Push Service
## Authentication & Authorization
- [x] Basic auth implemented for admin endpoints
- [x] VAPID authentication for push notifications
- [x] Environment variable for admin password
- [ ] Consider rate limiting for subscription endpoints
- [ ] Consider adding API key authentication for public endpoints
## Data Validation
- [x] Input validation for subscription data
- [x] Message size limits (100 chars)
- [x] Notification type validation
- [ ] Consider adding input sanitization for messages
## Database Security
- [x] SQLite database with configurable path
- [x] No raw SQL queries (uses SQLAlchemy ORM)
- [ ] Consider adding database connection pooling
- [ ] Consider encryption at rest for sensitive data
## Push Notification Security
- [x] VAPID key rotation capability
- [x] Secure key generation using cryptography library
- [x] Proper error handling for expired subscriptions
- [ ] Consider adding payload encryption
## General Security
- [x] Type hints for better code safety
- [x] Error logging implemented
- [ ] Consider adding request logging
- [ ] Consider adding CORS protection
- [ ] Consider adding CSP headers

845
app.py

File diff suppressed because it is too large

71
models.py

@ -1,25 +1,92 @@
"""
Database Models for Web Push Notification Service
This module defines the SQLAlchemy models for managing web push notifications,
including VAPID keys, user subscriptions, and application settings.
Author: Matthew Raymer
Created: 2025
"""
from flask_sqlalchemy import SQLAlchemy
from typing import List, Optional
db = SQLAlchemy()
class VAPIDKey(db.Model):
"""
Stores VAPID (Voluntary Application Server Identification) keys for
web push authentication.
VAPID keys are used to identify the application server to push services
and establish a trust relationship for sending notifications.
Attributes:
id (int): Primary key identifier
public_key (str): Base64-encoded public VAPID key (max 255 chars)
private_key (str): Base64-encoded private VAPID key (max 255 chars)
subscriptions (List[Subscription]): Related push notification subscriptions
"""
id = db.Column(db.Integer, primary_key=True)
public_key = db.Column(db.String(255), nullable=False)
private_key = db.Column(db.String(255), nullable=False)
subscriptions = db.relationship('Subscription', backref='vapid_key', lazy=True)
class Settings(db.Model):
"""
Application settings and state management for notification processing.
Tracks the execution state of notification jobs to prevent duplicate
processing and maintain notification history.
Attributes:
id (int): Primary key identifier
prev_notify_end_time (str): ISO 8601 timestamp of last completed notification run
running_notify_end_time (Optional[str]): ISO 8601 timestamp of currently running
notification job, or None if no job is running
"""
id = db.Column(db.Integer, primary_key=True)
prev_notify_end_time = db.Column(db.String(29), nullable=False)
running_notify_end_time = db.Column(db.String(29), nullable=True)
class Subscription(db.Model):
"""
User subscription details for web push notifications.
Stores the necessary information to send push notifications to a specific
browser/device, including encryption keys and notification preferences.
Attributes:
id (int): Primary key identifier
auth (str): Authentication secret for push encryption (max 255 chars)
created_date (Optional[str]): ISO 8601 timestamp of subscription creation
endpoint (str): Push service URL for this subscription (max 500 chars)
message (Optional[str]): Custom message for direct notifications (max 100 chars)
notify_time (str): Daily notification time in "HH:MM" format (UTC)
notify_type (Optional[str]): Type of notification subscription
Valid values:
- 'DAILY_CHECK': Regular daily notifications
- 'DIRECT_NOTIFICATION': One-time direct notifications
p256dh (str): Client's public key for push encryption (max 255 chars)
vapid_key_id (int): Foreign key reference to associated VAPID key
Relationships:
vapid_key: References the VAPID key used for this subscription
Note:
The endpoint URL is unique per browser/device/user combination and
serves as the primary identifier for the subscription from the
push service's perspective.
"""
id = db.Column(db.Integer, primary_key=True)
auth = db.Column(db.String(255), nullable=False)
created_date = db.Column(db.String(29), nullable=True)
endpoint = db.Column(db.String(500), nullable=False)
message = db.Column(db.String(100), nullable=True)
notify_time = db.Column(db.String(5), nullable=False) # HH:MM
notify_type = db.Column(db.String(32), nullable=True) # 'DAILY_CHECK', 'DIRECT_NOTIFICATION'
notify_time = db.Column(db.String(5), nullable=False) # HH:MM
notify_type = db.Column(db.String(32), nullable=True) # 'DAILY_CHECK', 'DIRECT_NOTIFICATION'
p256dh = db.Column(db.String(255), nullable=False)
vapid_key_id = db.Column(db.Integer, db.ForeignKey('vapid_key.id'), nullable=False)

1
requirements.txt

@ -3,3 +3,4 @@ flask>=2.0.0
flask_sqlalchemy
pywebpush
gunicorn
structlog>=24.1.0

Loading…
Cancel
Save