#!/bin/bash

# OpenVPN Certificate Management Script
# Lambicall VPN Manager

EASYRSA_DIR="/etc/openvpn/easy-rsa"
PKI_DIR="$EASYRSA_DIR/pki"
OPENVPN_DIR="/etc/openvpn"
CLIENT_DIR="/var/www/html/openvpn/certificates/clients"
LOG_FILE="/var/log/openvpn/manager.log"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

# Logging function
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}

# Initialize EasyRSA
init_pki() {
    echo -e "${GREEN}Initializing PKI...${NC}"
    cd "$EASYRSA_DIR"
    ./easyrsa init-pki
    ./easyrsa build-ca nopass
    ./easyrsa gen-dh
    ./easyrsa build-server-full server nopass
    openvpn --genkey --secret "$OPENVPN_DIR/ta.key"
    log_message "PKI initialized successfully"
}

# Generate client certificate
generate_client() {
    CLIENT_NAME=$1
    
    if [ -z "$CLIENT_NAME" ]; then
        echo -e "${RED}Error: Client name required${NC}"
        return 1
    fi
    
    echo -e "${GREEN}Generating certificate for $CLIENT_NAME...${NC}"
    cd "$EASYRSA_DIR"
    
    # Check if client already exists
    if [ -f "$PKI_DIR/issued/$CLIENT_NAME.crt" ]; then
        echo -e "${YELLOW}Certificate already exists for $CLIENT_NAME${NC}"
        return 1
    fi
    
    # Generate client certificate
    ./easyrsa build-client-full "$CLIENT_NAME" nopass
    
    # Create client directory
    mkdir -p "$CLIENT_DIR/$CLIENT_NAME"
    
    # Copy certificates
    cp "$PKI_DIR/ca.crt" "$CLIENT_DIR/$CLIENT_NAME/"
    cp "$PKI_DIR/issued/$CLIENT_NAME.crt" "$CLIENT_DIR/$CLIENT_NAME/"
    cp "$PKI_DIR/private/$CLIENT_NAME.key" "$CLIENT_DIR/$CLIENT_NAME/"
    cp "$OPENVPN_DIR/ta.key" "$CLIENT_DIR/$CLIENT_NAME/"
    
    log_message "Certificate generated for $CLIENT_NAME"
    echo -e "${GREEN}Certificate generated successfully${NC}"
    
    # Generate configuration files
    generate_ovpn "$CLIENT_NAME"
    generate_inline_conf "$CLIENT_NAME"
}

# Generate .ovpn file
generate_ovpn() {
    CLIENT_NAME=$1
    SERVER_IP=$(curl -s ifconfig.me)
    OUTPUT_FILE="$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.ovpn"
    
    cat > "$OUTPUT_FILE" << EOF
client
dev tun
proto udp
remote $SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
comp-lzo
verb 3
key-direction 1

<ca>
$(cat "$CLIENT_DIR/$CLIENT_NAME/ca.crt")
</ca>

<cert>
$(cat "$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.crt")
</cert>

<key>
$(cat "$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.key")
</key>

<tls-auth>
$(cat "$CLIENT_DIR/$CLIENT_NAME/ta.key")
</tls-auth>
EOF
    
    log_message "OVPN file generated for $CLIENT_NAME"
    echo -e "${GREEN}OVPN file generated: $OUTPUT_FILE${NC}"
}

# Generate inline .conf file for Windows/Linux
generate_inline_conf() {
    CLIENT_NAME=$1
    SERVER_IP=$(curl -s ifconfig.me)
    OUTPUT_FILE="$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.conf"
    
    cat > "$OUTPUT_FILE" << EOF
# OpenVPN Client Configuration
# Generated for: $CLIENT_NAME
# Server: vpn.lambicall.com

client
dev tun
proto udp
remote $SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
comp-lzo
verb 3
key-direction 1

# Redirect all traffic through VPN
redirect-gateway def1
dhcp-option DNS 8.8.8.8
dhcp-option DNS 8.8.4.4

<ca>
$(cat "$CLIENT_DIR/$CLIENT_NAME/ca.crt")
</ca>

<cert>
$(cat "$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.crt")
</cert>

<key>
$(cat "$CLIENT_DIR/$CLIENT_NAME/$CLIENT_NAME.key")
</key>

<tls-auth>
$(cat "$CLIENT_DIR/$CLIENT_NAME/ta.key")
</tls-auth>
EOF
    
    log_message "CONF file generated for $CLIENT_NAME"
    echo -e "${GREEN}CONF file generated: $OUTPUT_FILE${NC}"
}

# Revoke client certificate
revoke_client() {
    CLIENT_NAME=$1
    
    if [ -z "$CLIENT_NAME" ]; then
        echo -e "${RED}Error: Client name required${NC}"
        return 1
    fi
    
    echo -e "${YELLOW}Revoking certificate for $CLIENT_NAME...${NC}"
    cd "$EASYRSA_DIR"
    
    # Check if client exists
    if [ ! -f "$PKI_DIR/issued/$CLIENT_NAME.crt" ]; then
        echo -e "${RED}Certificate not found for $CLIENT_NAME${NC}"
        return 1
    fi
    
    # Revoke certificate
    ./easyrsa revoke "$CLIENT_NAME"
    ./easyrsa gen-crl
    
    # Copy CRL to OpenVPN
    cp "$PKI_DIR/crl.pem" "$OPENVPN_DIR/"
    
    # Remove client files
    rm -rf "$CLIENT_DIR/$CLIENT_NAME"
    
    log_message "Certificate revoked for $CLIENT_NAME"
    echo -e "${GREEN}Certificate revoked successfully${NC}"
    
    # Restart OpenVPN to apply changes
    systemctl restart openvpn@server
}

# List all clients
list_clients() {
    echo -e "${GREEN}Active VPN Clients:${NC}"
    echo "-------------------"
    
    for cert in "$PKI_DIR/issued"/*.crt; do
        if [ -f "$cert" ]; then
            CLIENT=$(basename "$cert" .crt)
            if [ "$CLIENT" != "server" ]; then
                echo "- $CLIENT"
            fi
        fi
    done
}

# Get client status
client_status() {
    CLIENT_NAME=$1
    
    if [ -z "$CLIENT_NAME" ]; then
        list_clients
        return
    fi
    
    if [ -f "$PKI_DIR/issued/$CLIENT_NAME.crt" ]; then
        echo -e "${GREEN}Client $CLIENT_NAME: Active${NC}"
        
        # Check if currently connected
        if grep -q "^$CLIENT_NAME," /var/log/openvpn/openvpn-status.log 2>/dev/null; then
            echo -e "${GREEN}Status: Connected${NC}"
            grep "^$CLIENT_NAME," /var/log/openvpn/openvpn-status.log
        else
            echo -e "${YELLOW}Status: Disconnected${NC}"
        fi
    else
        echo -e "${RED}Client $CLIENT_NAME: Not found${NC}"
    fi
}

# Package client files
package_client() {
    CLIENT_NAME=$1
    OUTPUT_FORMAT=$2  # zip or tar
    
    if [ -z "$CLIENT_NAME" ]; then
        echo -e "${RED}Error: Client name required${NC}"
        return 1
    fi
    
    if [ ! -d "$CLIENT_DIR/$CLIENT_NAME" ]; then
        echo -e "${RED}Client files not found${NC}"
        return 1
    fi
    
    cd "$CLIENT_DIR"
    
    if [ "$OUTPUT_FORMAT" == "zip" ]; then
        zip -r "$CLIENT_NAME.zip" "$CLIENT_NAME/"
        echo -e "${GREEN}Package created: $CLIENT_DIR/$CLIENT_NAME.zip${NC}"
    else
        tar -czf "$CLIENT_NAME.tar.gz" "$CLIENT_NAME/"
        echo -e "${GREEN}Package created: $CLIENT_DIR/$CLIENT_NAME.tar.gz${NC}"
    fi
    
    log_message "Client files packaged for $CLIENT_NAME"
}

# Main menu
show_help() {
    echo "OpenVPN Manager - Lambicall VPN"
    echo "Usage: $0 [command] [options]"
    echo ""
    echo "Commands:"
    echo "  init                    Initialize PKI and CA"
    echo "  generate <client>       Generate new client certificate"
    echo "  revoke <client>         Revoke client certificate"
    echo "  list                    List all clients"
    echo "  status [client]         Show client status"
    echo "  package <client> [zip]  Package client files"
    echo "  help                    Show this help"
}

# Main script logic
case "$1" in
    init)
        init_pki
        ;;
    generate)
        generate_client "$2"
        ;;
    revoke)
        revoke_client "$2"
        ;;
    list)
        list_clients
        ;;
    status)
        client_status "$2"
        ;;
    package)
        package_client "$2" "$3"
        ;;
    help|--help|-h)
        show_help
        ;;
    *)
        show_help
        exit 1
        ;;
esac