#!/system/bin/sh

# 应用标识常量，用于标识具体应用
APPID="应用标识常量"
# 应用密钥，用于签名验证
APPKEY="应用KEY"
# RC4加密开关，控制是否使用RC4加密
RC4_SWITCH=true
# RC4加密密钥
RC4_KEY="应用KEY"
# 脚本版本号
VERSION="1.0"

# 设备标识码存储文件路径
MARKCODE_FILE="/storage/emulated/0/Android/imei"
# 卡密记录文件路径，保存验证成功的卡密
KMLJ="/storage/emulated/0/Android/km.txt"

# 获取设备标识码函数
# 原理：检查设备标识文件是否存在且非空，如果存在则读取内容，不存在则生成随机6位数字作为标识码
# 运行流程：
# 1. 检查标记文件是否存在且大小非零
# 2. 如果文件存在，直接读取文件内容作为标识码
# 3. 如果文件不存在，生成0-999999的随机数作为标识码
# 4. 创建文件目录（如果不存在）并将标识码写入文件
# 5. 返回设备标识码
get_markcode() {
    # 检查设备标识文件是否存在且非空
    if [ -f "$MARKCODE_FILE" ] && [ -s "$MARKCODE_FILE" ]; then
        # 读取文件内容作为设备标识码
        cat "$MARKCODE_FILE"
    else
        # 生成0-999999的随机数作为设备标识码
        markcode=$((RANDOM % 1000000))
        # 创建文件目录（如果不存在）
        mkdir -p "$(dirname "$MARKCODE_FILE")"
        # 将设备标识码写入文件
        echo "$markcode" > "$MARKCODE_FILE"
        # 返回设备标识码
        echo "$markcode"
    fi
}

# 调用函数获取设备标识码并存储在变量MARKCODE中
MARKCODE=$(get_markcode)

# 生成签名函数
# 参数：卡密、设备标识码、应用密钥
# 原理：使用MD5算法生成请求签名，防止请求被篡改
# 运行流程：
# 1. 获取当前时间戳（秒级）
# 2. 按固定格式拼接字符串：kami=卡密&markcode=设备标识码&t=时间戳&应用密钥
# 3. 使用md5sum计算字符串的MD5哈希值
# 4. 提取并返回MD5值作为签名
get_sign() {
    local kami="$1" markcode="$2" appkey="$3"
    # 获取当前Unix时间戳
    local timestamp=$(date +%s)
    # 拼接签名字符串
    local sign_str="kami=${kami}&markcode=${markcode}&t=${timestamp}&${appkey}"
    # 计算MD5哈希值并返回
    echo -n "$sign_str" | md5sum | awk '{print $1}'
}

# RC4加密/解密函数
# 参数：要处理的数据、RC4密钥、是否加密（true为加密，false为解密）
# 原理：RC4流密码算法，通过初始化S盒和密钥流生成，实现对称加密
# 运行流程：
# 1. 重定向标准错误到/dev/null，屏蔽错误输出
# 2. 初始化S盒（0-255的排列）
# 3. 使用密钥对S盒进行初始置换（KSA算法）
# 4. 根据是否加密参数选择处理方式：
#    a. 加密：将每个字节与密钥流异或，输出十六进制字符串
#    b. 解密：将十六进制字符串转换为字节，与密钥流异或，转换为可打印字符
# 5. 恢复标准输出并返回处理结果
rc4_crypt() {
    {
        # 保存当前标准输出到文件描述符3，然后将标准输出重定向到/dev/null
        exec 3>&1
        exec 1>/dev/null 2>&1
        
        local data="$1" key="$2" encrypt="$3"
        local S i j k t byte result hexbyte
        
        # 初始化S盒，创建0-255的数组
        declare -a S
        for i in {0..255}; do S[$i]=$i; done
        
        # 将密钥字符串转换为字节数组
        local key_bytes=()
        for ((i=0; i<${#key}; i++)); do
            # 使用LC_ALL=C确保ASCII字符正确转换，错误时返回0
            byte=$(LC_ALL=C printf '%d' "'${key:i:1}" 2>/dev/null || echo 0)
            key_bytes[i]=$byte
        done
        
        # 使用密钥调度算法（KSA）初始化S盒
        j=0
        for i in {0..255}; do
            j=$(( (j + S[i] + key_bytes[i % ${#key}]) % 256 ))
            t=${S[i]}; S[i]=${S[j]}; S[j]=$t
        done
        
        i=0; j=0; result=""
        # 加密分支
        if [ "$encrypt" = "true" ]; then
            for ((k=0; k<${#data}; k++)); do
                # 获取明文字符的ASCII值
                byte=$(LC_ALL=C printf '%d' "'${data:k:1}" 2>/dev/null || echo 0)
                i=$(( (i + 1) % 256 ))
                j=$(( (j + S[i]) % 256 ))
                # 交换S[i]和S[j]
                t=${S[i]}; S[i]=${S[j]}; S[j]=$t
                # 生成密钥流字节并与明文字节异或，转换为两位十六进制
                printf -v result "%s%02x" "$result" $(( byte ^ S[(S[i]+S[j])%256] ))
            done
            # 将加密结果输出到文件描述符3（原标准输出）
            echo -n "$result" >&3
        # 解密分支
        else
            # 去除非十六进制字符，确保输入是有效的十六进制字符串
            hexdata=$(echo -n "$data" | tr -cd '[:xdigit:]')
            for ((k=0; k<${#hexdata}; k+=2)); do
                # 每次取两个十六进制字符
                hexbyte="${hexdata:k:2}"
                # 验证是否为有效的十六进制数
                if [[ "$hexbyte" =~ ^[0-9a-fA-F]{2}$ ]]; then
                    # 将十六进制转换为十进制
                    byte=$(( 0x$hexbyte ))
                    i=$(( (i + 1) % 256 ))
                    j=$(( (j + S[i]) % 256 ))
                    t=${S[i]}; S[i]=${S[j]}; S[j]=$t
                    # 异或解密
                    decrypted=$(( byte ^ S[(S[i]+S[j])%256] ))
                    # 处理特殊字符：null字节、控制字符、不可打印字符
                    if (( decrypted == 0 )); then
                        result+="\\000"
                    elif (( decrypted < 32 || decrypted > 126 )); then
                        # 使用八进制转义序列
                        printf -v result "%s\\%03o" "$result" "$decrypted"
                    else
                        # 使用十六进制转义序列
                        printf -v result "%s\\x%02x" "$result" "$decrypted"
                    fi
                fi
            done
            # 将转义序列转换为实际字符并输出到文件描述符3
            LC_ALL=C printf "%b" "$result" >&3 2>/dev/null
        fi
        
        # 恢复标准输出，关闭文件描述符3
        exec 1>&3 3>&-
    } 2>/dev/null
}

# 时间戳转换函数
# 参数：Unix时间戳
# 原理：根据系统类型（GNU或BSD）使用不同的date命令格式化时间戳
# 运行流程：
# 1. 检查date命令是否GNU版本（使用--version参数）
# 2. GNU系统使用-d @timestamp格式
# 3. BSD系统使用-r timestamp格式
# 4. 如果转换失败，返回"无效时间戳"
convert_timestamp() {
    local timestamp="$1"
    # 检测是否为GNU date版本
    if date --version 2>/dev/null | grep -q GNU; then
        # GNU日期格式：-d @时间戳
        date -d @"$timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null
    else
        # BSD日期格式：-r 时间戳
        date -r "$timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null
    fi || echo "无效时间戳"  # 转换失败时返回错误信息
}

# 提取JSON字段值函数
# 参数：JSON字符串、字段名
# 原理：使用grep和cut提取JSON中指定字段的值
# 运行流程：
# 1. 使用grep查找"字段名":"值"模式
# 2. 使用cut以双引号为分隔符提取第4个字段（值部分）
extract_json_field() {
    echo "$1" | grep -o "\"$2\":\"[^\"]*\"" | cut -d'"' -f4
}

# HTTP请求函数
# 参数：URL
# 原理：使用curl发送GET请求
# 运行流程：
# 1. 使用curl -s静默模式发送GET请求
# 2. 返回服务器响应内容
http_request() {
    curl -s -X GET "$1"
}

# 获取公告函数
# 原理：请求服务器公告API，使用RC4解密响应，提取公告内容
# 运行流程：
# 1. 构建公告API URL
# 2. 发送HTTP GET请求
# 3. 如果响应为空，返回失败
# 4. 使用RC4解密响应数据
# 5. 从解密后的JSON中提取app_gg字段（公告内容）
get_notice() {
    # 构建公告API URL，包含应用ID参数
    local notice_url="http://haraichi.top/api.php?api=notice&app=$APPID"
    # 发送HTTP请求获取公告
    local response=$(http_request "$notice_url")
    
    # 检查响应是否为空
    if [ -z "$response" ]; then
        echo "获取公告失败"
        return 1  # 返回非0表示失败
    fi
    
    # 使用RC4解密响应（false表示解密）
    decrypted=$(rc4_crypt "$response" "$RC4_KEY" "false")
    # 从解密后的JSON中提取app_gg字段（公告内容）
    notice=$(extract_json_field "$decrypted" "app_gg")
    echo "$notice"
}

# 获取版本信息函数
# 原理：请求服务器版本信息API，检查版本状态和更新说明
# 运行流程：
# 1. 构建版本信息API URL
# 2. 发送HTTP请求并获取响应
# 3. 使用RC4解密响应数据
# 4. 从JSON中提取code字段检查响应状态
# 5. 如果code为200（成功），提取更新说明并返回
get_version_info() {
    local xx_url="http://haraichi.top/api.php?api=ini&app=$APPID"
    local response=$(http_request "$xx_url")
    # 解密响应数据
    local decrypted=$(rc4_crypt "$response" "$RC4_KEY" "false")
    
    # 从JSON中提取code字段值
    local code=$(echo "$decrypted" | grep -o '"code":[^,]*' | cut -d':' -f2 | tr -d ' ')
    # 检查响应码是否为200（成功）
    if [ "$code" != "200" ]; then
        return 1  # 返回非0表示失败
    fi
    
    # 提取更新说明字段
    local update_notice=$(extract_json_field "$decrypted" "app_update_remark")
    echo "$update_notice"
}

# 卡密验证函数
# 原理：验证用户输入的卡密是否有效，验证成功则保存卡密到本地文件
# 运行流程：
# 1. 提示用户输入卡密
# 2. 生成时间戳和签名
# 3. 构建请求参数（按固定顺序：卡密、设备标识码、时间戳、签名）
# 4. 根据RC4开关选择是否加密请求数据
# 5. 发送验证请求到服务器
# 6. 解密并解析服务器响应
# 7. 根据响应码判断验证结果
# 8. 验证成功则保存卡密到文件
kmyz() {
    echo "请输入卡密:"
    read KM  # 读取用户输入的卡密
    
    # 获取当前时间戳
    local timestamp=$(date +%s)
    # 生成请求签名
    local sign=$(get_sign "$KM" "$MARKCODE" "$APPKEY")
    
    # 创建关联数组存储请求参数
    declare -A raw_data=(
        ["kami"]="$KM"
        ["markcode"]="$MARKCODE"
        ["t"]="$timestamp"
        ["sign"]="$sign"
    )
    
    # 定义参数顺序（确保签名计算和发送顺序一致）
    ordered_keys=("kami" "markcode" "t" "sign")
    # 构建POST参数字符串
    post_str=""
    for key in "${ordered_keys[@]}"; do
        post_str+="${key}=${raw_data[$key]}&"
    done
    post_str="${post_str%&}"  # 移除末尾的&
    
    # 根据RC4开关决定是否加密请求数据
    if $RC4_SWITCH; then
        # 加密数据并构建参数
        Rc4encrypt="data=$(rc4_crypt "$post_str" "$RC4_KEY" "true")"
    else
        Rc4encrypt="$post_str"
    fi
    
    # 构建完整的卡密验证URL，添加随机值防止缓存
    local km_url="http://haraichi.top/api.php?api=kmlogon&app=$APPID&$Rc4encrypt&value=$((RANDOM % 1000000))"
    local response=$(http_request "$km_url")
    
    # 检查响应是否为空
    if [ -z "$response" ]; then
        echo "获取响应失败"
        return 1
    fi
    
    # 解密响应数据
    local decrypted=$(rc4_crypt "$response" "$RC4_KEY" "false")
    # 提取响应码
    local code=$(echo "$decrypted" | grep -o '"code":[^,]*' | cut -d':' -f2 | tr -d ' ')
    # 检查响应码是否为200（成功）
    if [ "$code" = "200" ]; then
        # 提取卡密和VIP到期时间
        local kami=$(extract_json_field "$decrypted" "kami")
        local vip=$(extract_json_field "$decrypted" "vip")
        echo "验证成功"
        echo "卡密: $kami"
        echo "到期时间: $(convert_timestamp "$vip")"
        
        # 将验证成功的卡密保存到文件
        echo "$KM" > "$KMLJ"
        
        return 0  # 返回0表示成功
    else
        # 提取错误信息
        local msg=$(extract_json_field "$decrypted" "msg")
        echo "验证失败"
        echo "原因: ${msg:-未知错误}"  # 如果msg为空，显示"未知错误"
        return 1  # 返回非0表示失败
    fi
}

# 卡密解绑函数
# 原理：将卡密从当前设备解绑，允许在其他设备使用
# 运行流程：
# 1. 提示用户输入要解绑的卡密
# 2. 生成时间戳和签名
# 3. 构建请求参数
# 4. 根据RC4开关决定是否加密
# 5. 发送解绑请求到服务器
# 6. 解析服务器响应并显示结果
kmjb() {
    echo "请输入解绑卡密:"
    read KM  # 读取用户输入的卡密
    
    # 获取当前时间戳
    local timestamp=$(date +%s)
    # 生成请求签名
    local sign=$(get_sign "$KM" "$MARKCODE" "$APPKEY")
    
    # 创建关联数组存储请求参数
    declare -A raw_data=(
        ["kami"]="$KM"
        ["markcode"]="$MARKCODE"
        ["t"]="$timestamp"
        ["sign"]="$sign"
    )
    
    # 定义参数顺序
    ordered_keys=("kami" "markcode" "t" "sign")
    # 构建POST参数字符串
    post_str=""
    for key in "${ordered_keys[@]}"; do
        post_str+="${key}=${raw_data[$key]}&"
    done
    post_str="${post_str%&}"
    
    # 根据RC4开关决定是否加密请求数据
    if $RC4_SWITCH; then
        Rc4encrypt="data=$(rc4_crypt "$post_str" "$RC4_KEY" "true")"
    else
        Rc4encrypt="$post_str"
    fi
    
    # 构建解绑请求URL
    local km_url="http://haraichi.top/api.php?api=kmunmachine&app=$APPID&$Rc4encrypt&value=$((RANDOM % 1000000))"
    local response=$(http_request "$km_url")
    
    # 解密响应数据
    local decrypted=$(rc4_crypt "$response" "$RC4_KEY" "false")
    # 提取响应码
    local code=$(echo "$decrypted" | grep -o '"code":[^,]*' | cut -d':' -f2 | tr -d ' ')
    # 检查响应码是否为200（成功）
    if [ "$code" = "200" ]; then
        echo "卡密 $KM 解绑成功"
        return 0
    else
        # 提取错误信息
        local msg=$(extract_json_field "$decrypted" "msg")
        echo "解绑失败: ${msg:-未知错误}"
        return 1
    fi
}

# 主验证系统函数
# 原理：提供用户交互界面，整合所有验证功能
# 运行流程：
# 1. 清屏并显示验证系统标题
# 2. 获取服务器公告和版本更新信息
# 3. 显示当前版本和公告信息
# 4. 提供菜单选项供用户选择
# 5. 根据用户选择执行相应功能
# 6. 验证成功后显示通过信息
加载主函数() {
    clear  # 清屏
    echo "━━━━━━━━━━━━━━"
    echo "至上·原一验证·你的项目名称"
    echo "━━━━━━━━━━━━━━"
    
    # 获取公告信息
    notice=$(get_notice)
    # 获取版本更新信息
    update_notice=$(get_version_info)
    
    # 显示信息
    echo "公告:$notice"
    echo "更新公告:$update_notice"
    echo "当前版本:$VERSION"
    echo ""
    
    # 主循环，等待用户选择
    while true; do
        echo "1. 输入授权密钥登录"
        echo "2. 解绑授权密钥"
        echo "3. 退出"
        echo ""
        echo "请选择对应的序号:"
        read choice  # 读取用户选择
        
        # 根据用户选择执行相应功能
        case "$choice" in
            1)
                # 调用卡密验证函数
                kmyz
                # 检查返回值，0表示成功
                case $? in
                    0) 
                        break ;;  # 验证成功，跳出循环
                esac
                ;;
            2)
                # 调用卡密解绑函数
                kmjb
                ;;
            3)
                echo "已退出"
                exit 0  # 退出脚本
                ;;
            *)
                echo "无效输入，请重新选择"
                ;;
        esac
    done
    
    # 验证通过后的处理
    clear
    echo "验证通过"
    echo "正在加载服务..."
}

# 脚本入口点：调用主验证系统函数
加载主函数