Improve security

This commit is contained in:
2025-09-21 17:48:36 +03:00
Unverified
parent 5e0d225b24
commit 991ef5dd0c
8 changed files with 20 additions and 45 deletions
+7 -35
View File
@@ -4,35 +4,18 @@ Generate VAPID keys for push notifications
Run this script to generate new VAPID keys for your application
"""
from pywebpush import WebPushException
import sys
import base64
import json
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
def generate_vapid_keys():
"""Generate VAPID keys for push notifications"""
try:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.backends import default_backend
# Generate private key
private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
# Get public key
public_key = private_key.public_key()
# Serialize keys
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# Convert to base64 for web push
private_key_b64 = base64.urlsafe_b64encode(
private_key.private_bytes(
@@ -50,23 +33,12 @@ def generate_vapid_keys():
public_key_b64 = base64.urlsafe_b64encode(public_key_raw).decode('utf-8').rstrip('=')
print("VAPID Keys Generated:")
print("=" * 50)
print(f"Private Key: {private_key_b64}")
print(f"Public Key: {public_key_b64}")
print("=" * 50)
print("\nAdd these to your environment variables:")
print(f"VAPID_PRIVATE_KEY={private_key_b64}")
print(f"VAPID_PUBLIC_KEY={public_key_b64}")
print(f"VAPID_PRIVATE_KEY=\"{private_key_b64}\"")
print(f"VAPID_PUBLIC_KEY=\"{public_key_b64}\"")
return private_key_b64, public_key_b64
except ImportError:
print("Error: cryptography library not found.")
print("Install it with: pip install cryptography")
return None, None
except Exception as e:
print(f"Error generating VAPID keys: {e}")
print(f"Error generating VAPID keys: {e}", file=sys.stderr)
return None, None
if __name__ == "__main__":
+7 -4
View File
@@ -10,11 +10,14 @@ logger = logging.getLogger("uvicorn.error")
class PushNotificationService:
def __init__(self):
# VAPID keys - load from environment variables
self.vapid_private_key = os.getenv("VAPID_PRIVATE_KEY", "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghg2CSKiq0KsXXXImE75Z8UAphGBjkpYjUE87zPBmGqKhRANCAATxbNBGMhNl6gLmPL0PAf2YIJCVYX_TZrSqkj7SCqsu5VNMhnDOan6Qc9hEkcTZgvwj286C24SnxfH5CghVMCI6")
self.vapid_public_key = os.getenv("VAPID_PUBLIC_KEY", "BPFs0EYyE2XqAuY8vQ8B_ZggkJVhf9NmtKqSPtIKqy7lU0yGcM5qfpBz2ESRxNmC_CPbzoLbhKfF8fkKCFUwIjo")
self.vapid_private_key = os.getenv("VAPID_PRIVATE_KEY")
self.vapid_public_key = os.getenv("VAPID_PUBLIC_KEY")
if (not self.vapid_public_key) or (not self.vapid_private_key):
raise ValueError("VAPID public or private key is None")
self.vapid_claims = {
"sub": "mailto:admin@fromchat.com",
"sub": "mailto:support@fromchat.ru",
"aud": "https://fcm.googleapis.com"
}
-1
View File
@@ -1 +0,0 @@
JWT_SECRET="jwt-secret-change-in-production"
@@ -2,7 +2,7 @@ import { useState, useEffect } from "react";
import { PRODUCT_NAME, API_BASE_URL } from "../../../core/config";
import type { DialogProps } from "../../../core/types";
import { MaterialDialog } from "../core/Dialog";
import { initialize, isSupported, startElectronReceiver, stopElectronReceiver, subscribe, unsubscribe } from "../../../utils/notifications";
import { initialize, isSupported, startElectronReceiver, stopElectronReceiver, subscribe, unsubscribe } from "../../../utils/push-notifications";
import { isElectron } from "../../../electron/electron";
import { useAppState } from "../../state";
import type { Switch } from "mdui/components/switch";
+1 -1
View File
@@ -8,7 +8,7 @@ import { useRef } from "react";
import type { TextField } from "mdui/components/text-field";
import { useAppState } from "../state";
import { MaterialTextField } from "../components/core/TextField";
import { initialize, isSupported, startElectronReceiver, subscribe } from "../../utils/notifications";
import { initialize, isSupported, startElectronReceiver, subscribe } from "../../utils/push-notifications";
import { isElectron } from "../../electron/electron";
export default function LoginScreen() {
+1 -1
View File
@@ -7,7 +7,7 @@ import { DMPanel, type DMPanelData } from "./panels/DMPanel";
import { getAuthHeaders } from "../auth/api";
import { restoreKeys } from "../auth/crypto";
import { API_BASE_URL } from "../core/config";
import { initialize, subscribe, startElectronReceiver, isSupported } from "../utils/notifications";
import { initialize, subscribe, startElectronReceiver, isSupported } from "../utils/push-notifications";
import { isElectron } from "../electron/electron";
type Page = "login" | "register" | "chat"
+3 -2
View File
@@ -27,8 +27,9 @@
"preview": "cd deployment && docker compose up --build --watch",
"preview:clean": "cd deployment && docker compose down -v",
"clean": "npm run backend:clean && npm run frontend:clean && npm run preview:clean",
"install": "npm run backend:dependencies && cp deployment/.env.example deployment/.env",
"prepare": "husky"
"install": "npm run backend:dependencies && npm run generate:env",
"prepare": "husky",
"generate:env": "echo \"JWT_SECRET=\\\"$(openssl rand -base64 32)\\\"\" > deployment/.env && ./.venv/bin/python3 backend/generate_vapid_keys.py 1>>deployment/.env"
},
"files": [
"frontend/build/electron"