diff --git a/app.py b/app.py index 3ef22d6..9c54d3f 100644 --- a/app.py +++ b/app.py @@ -42,7 +42,7 @@ class FlicButtonHandler: } # Ensure subscriptions file and directory exist - self.subscriptions_file = os.getenv('SUBSCRIPTIONS_FILE', '/app/subscriptions.json') + self.subscriptions_file = os.getenv('SUBSCRIPTIONS_FILE', 'app/subscriptions.json') self._ensure_subscriptions_file() # Load subscriptions @@ -70,26 +70,30 @@ class FlicButtonHandler: def _decode_vapid_private_key(self): """ - Decode and load the VAPID private key from base64 encoded string. - Returns the PEM-formatted private key as a string. + Load the VAPID private key from environment variable. + Handles the \n escaped format from .env file. """ try: - # Decode base64 private key - private_key_pem = base64.urlsafe_b64decode( - os.getenv('VAPID_PRIVATE_KEY', '').encode('utf-8') - ) + # Get the key from environment + env_key = os.getenv('VAPID_PRIVATE_KEY', '').strip() - # Load private key to validate it - private_key = serialization.load_pem_private_key( - private_key_pem, + # Convert escaped newlines back to actual newlines + private_pem = env_key.replace('\\n', '\n') + + # Verify PEM format + if not private_pem.startswith('-----BEGIN PRIVATE KEY-----'): + raise ValueError("Invalid PEM format") + + # Validate the key + serialization.load_pem_private_key( + private_pem.encode('utf-8'), password=None ) - # Return the original PEM string (pywebpush needs this format) - return private_key_pem.decode('utf-8') + return private_pem except Exception as e: - logger.error(f"Error loading VAPID private key: {e}") + logger.error(f"VAPID key error: {str(e)}") raise def load_subscriptions(self) -> List[Dict]: diff --git a/generate_vapid_keys.py b/generate_vapid_keys.py index 4ff985c..43074f7 100644 --- a/generate_vapid_keys.py +++ b/generate_vapid_keys.py @@ -31,26 +31,33 @@ def generate_vapid_keys(): # Generate EC private key private_key = ec.generate_private_key(ec.SECP256R1()) - # Serialize private key + # Serialize private key to PEM format private_pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption() - ) + ).decode('utf-8') + # Format for .env file (replace newlines with \n) + env_private_key = private_pem.strip().replace('\n', '\\n') + # Get public key public_key = private_key.public_key() - public_pem = public_key.public_bytes( + public_key_bytes = public_key.public_bytes( encoding=serialization.Encoding.X962, format=serialization.PublicFormat.UncompressedPoint ) - # Base64 encode keys - env_vars['VAPID_PRIVATE_KEY'] = base64.urlsafe_b64encode(private_pem).decode('utf-8') - env_vars['VAPID_PUBLIC_KEY'] = base64.urlsafe_b64encode(public_pem).decode('utf-8') - print("New VAPID keys generated and added to .env file.") + # Store keys + env_vars['VAPID_PRIVATE_KEY'] = env_private_key # Single-line format + env_vars['VAPID_PUBLIC_KEY'] = base64.urlsafe_b64encode(public_key_bytes).decode('utf-8') + + print("New VAPID keys generated in .env-compatible format.") else: - print("Existing VAPID keys found in .env file - no changes made.") + print("Existing VAPID keys found - no changes made.") + # Verify existing key format + if '-----BEGIN PRIVATE KEY-----' not in env_vars['VAPID_PRIVATE_KEY']: + print("Warning: Existing private key doesn't appear to be in PEM format!") # Ensure we have all required configuration variables with defaults if missing defaults = {