Files
flic-webhook-webpush/generate_vapid_keys.py
cpu 267d262fa6 first version
config

CORS

fixed key to one line

helper prints

clean up

logs

improved validations

again validations

fix

rewritten

flask and node.js solution

added subscription route

auth

flow diagrams
2025-03-31 23:00:03 +02:00

102 lines
4.0 KiB
Python

#!/usr/bin/env python3
import os
import base64
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
def generate_vapid_keys():
"""
Generate VAPID keys and update .env file, preserving existing variables.
Only regenerates keys if they are missing or empty.
"""
# Read existing .env file if it exists
env_vars = {}
if os.path.exists('.env'):
with open('.env', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#') and '=' in line:
key, value = line.split('=', 1)
env_vars[key.strip()] = value.strip()
# Check if we need to generate new keys
need_new_keys = (
'VAPID_PRIVATE_KEY' not in env_vars or
'VAPID_PUBLIC_KEY' not in env_vars or
not env_vars.get('VAPID_PRIVATE_KEY') or
not env_vars.get('VAPID_PUBLIC_KEY')
)
if need_new_keys:
# Generate EC private key
private_key = ec.generate_private_key(ec.SECP256R1(), backend=default_backend())
# Serialize private key to PEM format, but keep it clean
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
).decode('utf-8')
# Clean up PEM formatting for .env file
private_pem_clean = private_pem.replace('-----BEGIN PRIVATE KEY-----\n', '').replace('\n-----END PRIVATE KEY-----\n', '').replace('\n', '')
# Get public key
public_key = private_key.public_key()
public_key_bytes = public_key.public_bytes(
encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint
)
# Store keys
env_vars['VAPID_PRIVATE_KEY'] = private_pem_clean
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 - no changes made.")
# Ensure we have all required configuration variables with defaults if missing
defaults = {
# Flic Button Configuration
'FLIC_BUTTON1_SERIAL': env_vars.get('FLIC_BUTTON1_SERIAL', 'your_button1_serial'),
'FLIC_BUTTON2_SERIAL': env_vars.get('FLIC_BUTTON2_SERIAL', 'your_button2_serial'),
'FLIC_BUTTON3_SERIAL': env_vars.get('FLIC_BUTTON3_SERIAL', 'your_button3_serial'),
# Subscription Storage
'SUBSCRIPTIONS_FILE': env_vars.get('SUBSCRIPTIONS_FILE', 'data/subscriptions.json'),
# Logging Configuration
'LOG_LEVEL': env_vars.get('LOG_LEVEL', 'INFO'),
# VAPID Claim (email)
'VAPID_CLAIM_EMAIL': env_vars.get('VAPID_CLAIM_EMAIL', 'mailto:your-email@example.com')
}
# Update env_vars with defaults for any missing keys
env_vars.update({k: v for k, v in defaults.items() if k not in env_vars})
# Write back to .env file
with open('.env', 'w') as f:
f.write("# VAPID Keys for Web Push\n")
f.write(f"VAPID_PRIVATE_KEY={env_vars['VAPID_PRIVATE_KEY']}\n")
f.write(f"VAPID_PUBLIC_KEY={env_vars['VAPID_PUBLIC_KEY']}\n\n")
f.write("# Flic Button Configuration\n")
f.write(f"FLIC_BUTTON1_SERIAL={env_vars['FLIC_BUTTON1_SERIAL']}\n")
f.write(f"FLIC_BUTTON2_SERIAL={env_vars['FLIC_BUTTON2_SERIAL']}\n")
f.write(f"FLIC_BUTTON3_SERIAL={env_vars['FLIC_BUTTON3_SERIAL']}\n\n")
f.write("# Subscription Storage\n")
f.write(f"SUBSCRIPTIONS_FILE={env_vars['SUBSCRIPTIONS_FILE']}\n\n")
f.write("# Logging Configuration\n")
f.write(f"LOG_LEVEL={env_vars['LOG_LEVEL']}\n\n")
f.write("# VAPID Claim Email\n")
f.write(f"VAPID_CLAIM_EMAIL={env_vars['VAPID_CLAIM_EMAIL']}\n")
if __name__ == '__main__':
generate_vapid_keys()