#!/bin/bash
# ============================================================================
# 安全审计脚本 - 风七六本地生活服务平台
# 遵循阿里开发手册安全规范
# ============================================================================

set -euo pipefail

# 颜色输出
readonly RED="\033[31m"
readonly GREEN="\033[32m"
readonly YELLOW="\033[33m"
readonly BLUE="\033[34m"
readonly NC="\033[0m"

# 审计结果
declare -a audit_results=()
declare -i total_checks=0
declare -i passed_checks=0
declare -i failed_checks=0

# ============================================================================
# 日志函数
# ============================================================================
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
    passed_checks=$((passed_checks + 1))
}

log_failure() {
    echo -e "${RED}[FAILURE]${NC} $1"
    failed_checks=$((failed_checks + 1))
    audit_results+=("❌ $1")
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

# ============================================================================
# 检查函数
# ============================================================================

# 检查1: 代码中是否有硬编码密码
check_hardcoded_passwords() {
    log_info "检查代码中是否有硬编码密码..."
    total_checks=$((total_checks + 1))
    
    local found=0
    local patterns=(
        'password\s*=\s*["'"'"'][^"'\"'"']{8,}["'"'"']'
        'PASSWORD\s*=\s*["'"'"'][^"'\"'"']{8,}["'"'"']'
        'secret\s*=\s*["'"'"'][^"'\"'"']{16,}["'"'"']'
        'SECRET\s*=\s*["'"'"'][^"'\"'"']{16,}["'"'"']'
    )
    
    for pattern in "${patterns[@]}"; do
        local matches=$(grep -rnE "$pattern" \
            --include="*.java" --include="*.ts" --include="*.py" --include="*.sh" \
            --include="*.ps1" --include="*.yml" --include="*.yaml" \
            --include="*.json" --exclude-dir="node_modules" --exclude-dir="target" \
            --exclude-dir=".git" 2>/dev/null | head -20)
        
        if [[ -n "$matches" ]]; then
            found=1
            log_failure "发现可能存在硬编码密码:"
            echo "$matches" | while read -r line; do
                echo "  - $line"
            done
            break
        fi
    done
    
    if [[ $found -eq 0 ]]; then
        log_success "未发现硬编码密码"
    fi
}

# 检查2: .gitignore是否包含.env文件
check_gitignore_env() {
    log_info "检查.gitignore是否包含.env文件..."
    total_checks=$((total_checks + 1))
    
    local gitignore=".gitignore"
    
    if [[ ! -f "$gitignore" ]]; then
        log_failure ".gitignore文件不存在"
        return
    fi
    
    local env_check=$(grep -E '^\.env' "$gitignore")
    local env_pattern_check=$(grep -E '^\.env\.\*' "$gitignore")
    
    if [[ -z "$env_check" ]]; then
        log_failure ".gitignore中未配置.env文件排除规则"
        return
    fi
    
    if [[ -z "$env_pattern_check" ]]; then
        log_warn ".gitignore中未配置.env.*通配规则，建议添加"
    fi
    
    log_success ".gitignore配置检查通过"
}

# 检查3: 环境变量文件是否存在敏感信息
check_env_files() {
    log_info "检查环境变量文件是否存在敏感信息..."
    total_checks=$((total_checks + 1))
    
    local found=0
    
    for env_file in .env .env.local .env.* env/.env.*; do
        [[ -f "$env_file" ]] || continue
        
        # 检查是否包含实际密码值（非占位符）
        local sensitive_lines=$(grep -E '=.*[^$}{]' "$env_file" | grep -E '(PASSWORD|SECRET|TOKEN|KEY)' | grep -v '=\s*$' | grep -v '=\${' | head -10)
        
        if [[ -n "$sensitive_lines" ]]; then
            found=1
            log_warn "环境变量文件 $env_file 包含敏感配置（生产环境建议使用密钥管理服务）:"
            echo "$sensitive_lines" | while read -r line; do
                # 脱敏显示
                local masked=$(echo "$line" | sed 's/=.*$/=******/')
                echo "  - $masked"
            done
        fi
    done
    
    if [[ $found -eq 0 ]]; then
        log_success "环境变量文件检查通过"
    else
        passed_checks=$((passed_checks + 1))  # 这是警告，不是失败
    fi
}

# 检查4: JWT密钥长度检查
check_jwt_secret_length() {
    log_info "检查JWT密钥配置..."
    total_checks=$((total_checks + 1))
    
    local found=0
    
    for file in **/*.yml **/*.yaml **/*.properties 2>/dev/null; do
        [[ -f "$file" ]] || continue
        
        local jwt_secrets=$(grep -E 'jwt.*secret|JWT.*SECRET' "$file" | grep -v '${' | grep -v '$ENV{' | head -5)
        
        if [[ -n "$jwt_secrets" ]]; then
            found=1
            while read -r line; do
                local secret_value=$(echo "$line" | sed 's/.*=\s*//')
                local secret_length=${#secret_value}
                
                if [[ $secret_length -lt 32 ]]; then
                    log_failure "JWT密钥长度不足32位（当前${secret_length}位）: $file"
                elif [[ $secret_length -lt 64 ]]; then
                    log_warn "JWT密钥长度建议至少64位（当前${secret_length}位）: $file"
                fi
            done <<< "$jwt_secrets"
        fi
    done
    
    if [[ $found -eq 0 ]]; then
        log_success "未发现直接配置的JWT密钥（推荐做法）"
    else
        passed_checks=$((passed_checks + 1))
    fi
}

# 检查5: 密码复杂度检查（配置文件）
check_password_complexity() {
    log_info "检查密码复杂度..."
    total_checks=$((total_checks + 1))
    
    local found_weak=0
    
    # 检查示例配置文件中的密码
    for file in env/.env.example **/.env.example 2>/dev/null; do
        [[ -f "$file" ]] || continue
        
        local passwords=$(grep -E 'PASSWORD=|password=' "$file" | grep -v '^#' | grep -v '=\s*$' | sed 's/.*=\s*//')
        
        while read -r password; do
            [[ -z "$password" ]] && continue
            
            local len=${#password}
            local has_upper=$(echo "$password" | grep -q '[A-Z]' && echo 1 || echo 0)
            local has_lower=$(echo "$password" | grep -q '[a-z]' && echo 1 || echo 0)
            local has_digit=$(echo "$password" | grep -q '[0-9]' && echo 1 || echo 0)
            local has_special=$(echo "$password" | grep -q '[!@#$%^&*(),.?":{}|<>]' && echo 1 || echo 0)
            
            if [[ $len -lt 12 ]]; then
                log_warn "密码长度不足12位（${len}位）: $file"
                found_weak=1
            fi
            
            if [[ $((has_upper + has_lower + has_digit + has_special)) -lt 3 ]]; then
                log_warn "密码复杂度不足（建议包含大小写字母、数字、特殊字符）: $file"
                found_weak=1
            fi
        done <<< "$passwords"
    done
    
    if [[ $found_weak -eq 0 ]]; then
        log_success "密码复杂度检查通过"
    else
        passed_checks=$((passed_checks + 1))
    fi
}

# 检查6: Jenkinsfile安全检查
check_jenkinsfile_security() {
    log_info "检查Jenkinsfile安全配置..."
    total_checks=$((total_checks + 1))
    
    local jenkinsfile="infrastructure/jenkins/Jenkinsfile"
    
    if [[ ! -f "$jenkinsfile" ]]; then
        log_warn "Jenkinsfile不存在"
        passed_checks=$((passed_checks + 1))
        return
    fi
    
    local issues=0
    
    # 检查是否使用withCredentials
    if ! grep -q "withCredentials" "$jenkinsfile"; then
        log_failure "Jenkinsfile未使用withCredentials安全注入凭证"
        issues=1
    fi
    
    # 检查是否有硬编码密码
    if grep -E 'password\s*[:=]\s*["'"'"'][^"'\"'"']+["'"'"']' "$jenkinsfile" | grep -v 'escapeJson' | grep -v 'credentialsId' | grep -v 'passwordVariable' | grep -v 'usernamePassword' | grep -v 'string(' | grep -v 'file(' | grep -v 'sshUserPrivateKey(' | grep -q .; then
        log_failure "Jenkinsfile中可能存在硬编码密码"
        issues=1
    fi
    
    # 检查是否使用--password-stdin
    if grep -q "podman login" "$jenkinsfile" && ! grep -q "--password-stdin" "$jenkinsfile"; then
        log_warn "podman login建议使用--password-stdin方式传递密码"
    fi
    
    if [[ $issues -eq 0 ]]; then
        log_success "Jenkinsfile安全检查通过"
    fi
}

# 检查7: 前端配置安全检查
check_frontend_config() {
    log_info "检查前端配置安全..."
    total_checks=$((total_checks + 1))
    
    local issues=0
    
    # 检查前端是否有硬编码API密钥
    for file in frontend/**/*.ts frontend/**/*.js frontend/**/*.env.* 2>/dev/null; do
        [[ -f "$file" ]] || continue
        
        # 检查高德地图等API密钥
        if grep -E 'AMAP_KEY|amap.*key|map.*key' "$file" | grep -v 'import.meta.env' | grep -v 'process.env' | grep -v 'VITE_' | grep -q .; then
            log_warn "前端文件 $file 可能包含硬编码的API密钥"
            issues=1
        fi
        
        # 检查是否使用环境变量
        if grep -q 'VITE_MOCK_ADMIN_PASSWORD' "$file" || grep -q 'VITE_MOCK_OPERATOR_PASSWORD' "$file"; then
            log_info "前端演示密码已配置为环境变量: $file"
        fi
    done
    
    if [[ $issues -eq 0 ]]; then
        log_success "前端配置安全检查通过"
    else
        passed_checks=$((passed_checks + 1))
    fi
}

# 检查8: 脚本文件安全检查
check_script_security() {
    log_info "检查脚本文件安全..."
    total_checks=$((total_checks + 1))
    
    local issues=0
    
    # 检查是否有硬编码密码
    for file in scripts/**/*.sh infrastructure/scripts/**/*.py 2>/dev/null; do
        [[ -f "$file" ]] || continue
        
        # 检查是否使用环境变量
        if ! grep -q 'os.environ\|${.*PASSWORD.*}\|$PASSWORD\|export.*PASSWORD' "$file" 2>/dev/null; then
            # 检查是否有硬编码密码
            if grep -E 'password\s*=\s*["'"'"'][^"'\"'"']{8,}["'"'"']' "$file" | grep -v 'getenv' | grep -v 'os.environ' | grep -q .; then
                log_failure "脚本文件 $file 可能包含硬编码密码"
                issues=1
            fi
        fi
    done
    
    if [[ $issues -eq 0 ]]; then
        log_success "脚本文件安全检查通过"
    fi
}

# ============================================================================
# 主函数
# ============================================================================
main() {
    echo "=========================================="
    echo " 风七六本地生活服务平台 - 安全审计"
    echo "=========================================="
    echo ""
    
    # 执行检查
    check_hardcoded_passwords
    check_gitignore_env
    check_env_files
    check_jwt_secret_length
    check_password_complexity
    check_jenkinsfile_security
    check_frontend_config
    check_script_security
    
    # 输出报告
    echo ""
    echo "=========================================="
    echo "              审计报告"
    echo "=========================================="
    echo "检查总数: $total_checks"
    echo "通过: ${GREEN}$passed_checks${NC}"
    echo "失败: ${RED}$failed_checks${NC}"
    
    if [[ ${#audit_results[@]} -gt 0 ]]; then
        echo ""
        echo "问题列表:"
        for result in "${audit_results[@]}"; do
            echo "  $result"
        done
    fi
    
    echo ""
    if [[ $failed_checks -eq 0 ]]; then
        echo "${GREEN}✅ 所有检查通过！${NC}"
        echo "建议：定期执行安全审计，保持代码安全性"
    else
        echo "${RED}⚠️ 发现 $failed_checks 个安全问题，请及时修复${NC}"
    fi
    
    # 生成报告文件
    local report_file="security_audit_report_$(date +%Y%m%d_%H%M%S).md"
    generate_report "$report_file"
    echo ""
    echo "报告已保存至: $report_file"
}

# 生成报告文件
generate_report() {
    local report_file="$1"
    
    cat > "$report_file" << EOF
# 安全审计报告

## 基本信息
- 审计时间: $(date +%Y-%m-%d %H:%M:%S)
- 审计范围: 当前项目目录
- 检查总数: $total_checks
- 通过: $passed_checks
- 失败: $failed_checks

## 问题详情

EOF
    
    if [[ ${#audit_results[@]} -gt 0 ]]; then
        for result in "${audit_results[@]}"; do
            echo "- $result" >> "$report_file"
        done
    else
        echo "✅ 未发现安全问题" >> "$report_file"
    fi
    
    cat >> "$report_file" << EOF

## 审计结果
- **状态**: $(if [[ $failed_checks -eq 0 ]]; then echo "✅ 通过"; else echo "❌ 存在问题"; fi)
- **建议**: $(if [[ $failed_checks -eq 0 ]]; then echo "继续保持良好的安全实践"; else echo "请根据问题列表逐一修复"; fi)

## 后续建议
1. 定期执行安全审计（建议每周一次）
2. 在CI/CD流程中集成安全扫描
3. 定期轮换密钥和密码
4. 使用密钥管理服务管理敏感配置
EOF
}

# 执行主函数
main "$@"