Browse Source
			
			
			
			
				
		Comprehensive documentation update focusing on clarity and completeness while maintaining technical accuracy. Key improvements include: - Add detailed module-level documentation with features and dependencies - Enhance class-level documentation with responsibilities and endpoints - Improve method documentation with: - Clear workflow descriptions - Technical implementation details - Security considerations - Database impacts - Error handling specifics - Usage examples - Return type clarification - Thread safety notes Technical Changes: - Replace print statements with structured logging using structlog - Add specific error handling for SQLAlchemy and cryptography exceptions - Add type hints and improve return type annotations Security: - Document authentication requirements - Add security considerations sections - Clarify VAPID key handling - Document input validation Dependencies: - Add structlog>=24.1.0 to requirements.txt This improves code maintainability and helps future developers understand the system's security and operational characteristics.upgrade
				 4 changed files with 722 additions and 228 deletions
			
			
		@ -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  | 
				
			|||
								
									
										File diff suppressed because it is too large
									
								
							
						
					@ -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) | 
				
			|||
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue