VPN/main.py

115 lines
4.4 KiB
Python
Raw Normal View History

2025-09-27 16:06:32 +00:00
"""
FastAPI server for the VPN Access Server.
2025-09-27 16:06:32 +00:00
"""
import uvicorn
2025-09-27 16:06:32 +00:00
import os
2025-10-20 06:07:48 +00:00
import logging
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
2025-09-27 16:06:32 +00:00
from util.client.generate_client import generate_client_config
2025-10-20 04:47:54 +00:00
from util.email import send_vpn_config
2025-10-20 06:07:48 +00:00
from access.config import config
from access.utils import setup_logging
app = FastAPI(
title="VPN Access Server API",
description="API for managing VPN clients and server operations.",
version="1.0.0",
)
2025-10-20 06:07:48 +00:00
# Set up logging - use local logs directory if system log path is not writable
log_file = config.server.log_file
if log_file and not os.path.exists(os.path.dirname(log_file)):
log_file = "logs/vpn-access-server.log"
logger = setup_logging(
log_level=config.server.log_level,
log_file=log_file
)
class ClientRequest(BaseModel):
username: str
email: str
@app.post("/api/client/generate", summary="Generate a new VPN client configuration")
def generate_client(request: ClientRequest):
"""
2025-10-20 04:47:54 +00:00
Generates a new OpenVPN client configuration (.ovpn) file and sends it via email.
This endpoint will:
1. Trigger `easyrsa` to generate a new client certificate and key.
2. Assemble the `.ovpn` file with the new certificate/key and the server's CA and TA keys.
3. Save the file to the server's client configuration directory.
2025-10-20 04:47:54 +00:00
4. Send the .ovpn file and user guide via email to the provided email address.
"""
2025-10-20 06:07:48 +00:00
logger.info(f"Client generation request for user: {request.username}, email: {request.email}")
success, message = generate_client_config(request.username, request.email)
if not success:
2025-10-20 06:07:48 +00:00
logger.error(f"Client generation failed for user {request.username}: {message}")
raise HTTPException(status_code=500, detail=message)
2025-10-20 04:47:54 +00:00
2025-10-20 06:07:48 +00:00
logger.info(f"Client generation successful for user {request.username}: {message}")
# Check if email configuration is valid
if not config.email.smtp_username or not config.email.smtp_password:
logger.warning(f"Email not configured - skipping email send for user {request.username}")
return {
"message": f"{message} Note: Email not sent - SMTP credentials not configured in .env file.",
"email_sent": False,
"warning": "Configure SMTP_USERNAME and SMTP_PASSWORD in .env to enable email notifications"
}
2025-10-20 04:47:54 +00:00
# Send email with VPN config and user guide
vpn_config_path = os.path.join("generated-clients", f"{request.username}.ovpn")
user_guide_path = "material/sample-ppt.pptx"
2025-10-20 06:07:48 +00:00
logger.info(f"Attempting to send email to {request.email} for user {request.username}")
try:
email_success = send_vpn_config(
to_email=request.email,
username=request.username,
vpn_config_path=vpn_config_path,
user_guide_path=user_guide_path
)
except Exception as e:
# Email sending failed with exception
logger.error(f"Email sending failed for user {request.username}: {str(e)}")
return {
"message": f"{message} Warning: Failed to send email - {str(e)}",
"email_sent": False
}
2025-10-20 04:47:54 +00:00
if not email_success:
# Configuration was generated successfully, but email failed
2025-10-20 06:07:48 +00:00
logger.warning(f"Email sending returned false for user {request.username}")
2025-10-20 04:47:54 +00:00
return {
"message": f"{message} Warning: Failed to send email with configuration files.",
"email_sent": False
}
2025-10-20 06:07:48 +00:00
logger.info(f"Email sent successfully to {request.email} for user {request.username}")
2025-10-20 04:47:54 +00:00
return {
"message": f"{message} Configuration files sent to {request.email}",
"email_sent": True
}
@app.get("/api/client/get-config/{username}", summary="Download a client configuration file")
def get_client_config(username: str, email: str):
"""
Downloads the .ovpn configuration file for a specific client.
The file is sought in the `generated-clients` directory.
"""
file_path = os.path.join("generated-clients", f"{username}.ovpn")
if not os.path.isfile(file_path):
raise HTTPException(status_code=404, detail="Configuration file not found for this user. Please generate it first.")
return FileResponse(path=file_path, filename=f"{username}.ovpn", media_type='application/octet-stream')
2025-09-27 16:06:32 +00:00
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8443)