import base64 from cryptography.hazmat.primitives import serialization from django.core.management.base import BaseCommand from py_vapid import Vapid01 def b64(raw: bytes) -> str: """base64url without padding — the encoding both the browser and py_vapid want.""" return base64.urlsafe_b64encode(raw).decode().rstrip("=") class Command(BaseCommand): help = "Generate a VAPID key pair for Web Push. Run once, then keep the values." def handle(self, *args, **options): vapid = Vapid01() vapid.generate_keys() # The private scalar, raw: py_vapid's from_string() takes exactly this. private = vapid.private_key.private_numbers().private_value.to_bytes(32, "big") # The public point, uncompressed: what the browser wants as # applicationServerKey when subscribing. public = vapid.public_key.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint, ) self.stdout.write( self.style.SUCCESS( "Add these to the environment (keep the private key secret):\n" ) ) self.stdout.write(f"VAPID_PUBLIC_KEY={b64(public)}") self.stdout.write(f"VAPID_PRIVATE_KEY={b64(private)}") self.stdout.write( "\nChanging these later invalidates every existing subscription: " "each device would have to re-enable reminders." )