.版本 2 ' ============================================================ ' 阿越云验证 - 易语言 SDK ' ' 支持:卡密登录、心跳保活、公告获取、版本检查(含强制更新)、 ' 卡密解绑、获取应用配置 ' ' 使用说明: ' 1. 本文件需与「阿越云验证易语言模块.ec」配套使用 ' 2. 或直接复制以下子程序到你的项目中(依赖精易模块) ' ' @version 1.0.0 ' ============================================================ .程序集 阿越云验证 .程序集变量 全局_服务器地址, 文本型 .程序集变量 全局_应用ID, 整数型 .程序集变量 全局_应用密钥, 文本型 .程序集变量 全局_通信密钥, 文本型 .程序集变量 全局_加密类型, 整数型 .程序集变量 全局_是否签名, 逻辑型 .程序集变量 全局_最后错误, 文本型 .程序集变量 全局_最后状态码, 整数型 ' ============================================================ ' 初始化 ' ============================================================ .子程序 初始化, , 公开 .参数 服务器地址, 文本型 .参数 应用ID, 整数型 .参数 应用密钥, 文本型, 可空 .参数 通信密钥, 文本型, 可空 .参数 加密类型, 整数型, 可空 .参数 是否签名, 逻辑型, 可空 如果真 (取文本右边 (服务器地址, 1) ≠ “/”) 服务器地址 = 服务器地址 + “/” 如果真结束 全局_服务器地址 = 服务器地址 全局_应用ID = 应用ID 全局_应用密钥 = 应用密钥 全局_通信密钥 = 通信密钥 如果 (是否为空 (加密类型)) 全局_加密类型 = 0 否则 全局_加密类型 = 加密类型 如果结束 全局_是否签名 = 是否签名 ' ============================================================ ' 卡密登录 ' ============================================================ .子程序 卡密登录, 逻辑型, 公开 .参数 卡密, 文本型 .参数 设备码, 文本型 .参数 返回信息, 文本型, 参考 .参数 到期时间戳, 整数型, 参考 .局部变量 请求数据, 文本型 .局部变量 响应, 文本型 .局部变量 状态码, 整数型 请求数据 = “kami=” + 编码_URL编码 (卡密) + “&markcode=” + 编码_URL编码 (设备码) 响应 = 发送请求 (“kmlogon”, 请求数据) 状态码 = 解析_状态码 (响应) 全局_最后状态码 = 状态码 如果真 (状态码 ≠ 200) 返回信息 = 解析_消息 (响应) 返回 (假) 如果真结束 返回信息 = 解析_字段 (响应, “message”) 到期时间戳 = 到整数 (解析_字段 (响应, “expires_ts”)) 返回 (真) ' ============================================================ ' 心跳保活 ' ============================================================ .子程序 心跳, 逻辑型, 公开 .参数 卡密, 文本型 .参数 设备码, 文本型 .参数 返回信息, 文本型, 参考 .参数 到期时间戳, 整数型, 参考 .局部变量 请求数据, 文本型 .局部变量 响应, 文本型 .局部变量 状态码, 整数型 请求数据 = “kami=” + 编码_URL编码 (卡密) + “&markcode=” + 编码_URL编码 (设备码) 响应 = 发送请求 (“heartbeat”, 请求数据) 状态码 = 解析_状态码 (响应) 全局_最后状态码 = 状态码 如果真 (状态码 ≠ 200) 返回信息 = 解析_消息 (响应) 返回 (假) 如果真结束 返回信息 = 解析_字段 (响应, “message”) 到期时间戳 = 到整数 (解析_字段 (响应, “expires_ts”)) 返回 (真) ' ============================================================ ' 退出心跳 ' ============================================================ .子程序 退出心跳, 逻辑型, 公开 .参数 卡密, 文本型 .局部变量 信息, 文本型 .局部变量 时间戳, 整数型 返回 (心跳 (卡密, “quit”, 信息, 时间戳)) ' ============================================================ ' 获取公告 ' ============================================================ .子程序 取公告, 文本型, 公开 .局部变量 响应, 文本型 .局部变量 状态码, 整数型 响应 = 发送请求 (“notice”, “”) 状态码 = 解析_状态码 (响应) 全局_最后状态码 = 状态码 如果真 (状态码 ≠ 200) 返回 (“”) 如果真结束 返回 (解析_字段 (响应, “app_gg”)) ' ============================================================ ' 检查更新 ' ============================================================ .子程序 检查更新, 逻辑型, 公开 .参数 当前版本, 文本型 .参数 有新版本, 逻辑型, 参考 .参数 强制更新, 逻辑型, 参考 .参数 最新版本, 文本型, 参考 .参数 更新地址, 文本型, 参考 .参数 更新说明, 文本型, 参考 .局部变量 响应, 文本型 .局部变量 状态码, 整数型 .局部变量 服务器版本, 文本型 .局部变量 强制标记, 文本型 响应 = 发送请求 (“ini”, “”) 状态码 = 解析_状态码 (响应) 全局_最后状态码 = 状态码 如果真 (状态码 ≠ 200) 返回 (假) 如果真结束 服务器版本 = 解析_字段 (响应, “version”) 更新地址 = 解析_字段 (响应, “app_update_url”) 更新说明 = 解析_字段 (响应, “app_update_show”) 强制标记 = 解析_字段 (响应, “app_update_must”) 最新版本 = 服务器版本 有新版本 = (版本比较 (服务器版本, 当前版本) > 0) 强制更新 = (有新版本 且 强制标记 = “y”) 返回 (真) ' ============================================================ ' 卡密解绑 ' ============================================================ .子程序 卡密解绑, 逻辑型, 公开 .参数 卡密, 文本型 .参数 设备码, 文本型 .参数 返回信息, 文本型, 参考 .局部变量 请求数据, 文本型 .局部变量 响应, 文本型 .局部变量 状态码, 整数型 请求数据 = “kami=” + 编码_URL编码 (卡密) + “&markcode=” + 编码_URL编码 (设备码) 响应 = 发送请求 (“kmunmachine”, 请求数据) 状态码 = 解析_状态码 (响应) 全局_最后状态码 = 状态码 如果真 (状态码 ≠ 200) 返回信息 = 解析_消息 (响应) 返回 (假) 如果真结束 返回信息 = “解绑成功” 返回 (真) ' ============================================================ ' 版本比较 ' ============================================================ .子程序 版本比较, 整数型, 公开 .参数 版本1, 文本型 .参数 版本2, 文本型 .局部变量 数组1, 文本型, , "0" .局部变量 数组2, 文本型, , "0" .局部变量 数量, 整数型 .局部变量 i, 整数型 .局部变量 值1, 整数型 .局部变量 值2, 整数型 数组1 = 分割文本 (版本1, “.”, ) 数组2 = 分割文本 (版本2, “.”, ) 数量 = 取数组成员数 (数组1) 如果真 (取数组成员数 (数组2) > 数量) 数量 = 取数组成员数 (数组2) 如果真结束 .计次循环首 (数量, i) 如果 (i ≤ 取数组成员数 (数组1)) 值1 = 到整数 (数组1 [i]) 否则 值1 = 0 如果结束 如果 (i ≤ 取数组成员数 (数组2)) 值2 = 到整数 (数组2 [i]) 否则 值2 = 0 如果结束 如果真 (值1 > 值2) 返回 (1) 如果真结束 如果真 (值1 < 值2) 返回 (-1) 如果真结束 .计次循环尾 () 返回 (0) ' ============================================================ ' 底层:发送请求 ' ============================================================ .子程序 发送请求, 文本型 .参数 接口名, 文本型 .参数 附加数据, 文本型 .局部变量 完整地址, 文本型 .局部变量 请求体, 文本型 .局部变量 随机值, 文本型 .局部变量 签名, 文本型 .局部变量 返回数据, 文本型 全局_最后错误 = “” 全局_最后状态码 = 0 随机值 = 取随机文本 (16) 完整地址 = 全局_服务器地址 + “api.php?api=” + 编码_URL编码 (接口名) + “&app=” + 到文本 (全局_应用ID) 如果 (全局_加密类型 = 0) ' 明文模式 请求体 = 附加数据 + “&value=” + 随机值 如果真 (全局_是否签名) 签名 = 生成签名 (请求体) 请求体 = 请求体 + “&sign=” + 签名 如果真结束 否则 ' 加密模式 如果 (全局_加密类型 = 1) 请求体 = “data=” + 编码_URL编码 (RC4加密 (附加数据 + “&value=” + 随机值, 全局_通信密钥)) 否则 请求体 = “data=” + 编码_URL编码 (编码_BASE64编码 (到字节集 (附加数据 + “&value=” + 随机值))) 如果结束 请求体 = 请求体 + “&value=” + 随机值 如果真 (全局_是否签名) 签名 = 生成签名 (附加数据 + “&value=” + 随机值 + “&data=” + 解析_URL解码 (请求体)) 请求体 = 请求体 + “&sign=” + 签名 如果真结束 如果结束 返回数据 = 网页_访问S (完整地址, 1, 请求体, , , “User-Agent: AyueVerify-EPL-SDK/1.0.0”, , , , , , , , , ) 如果真 (返回数据 = “”) 全局_最后错误 = “网络请求失败” 全局_最后状态码 = -1 返回 (“{”“code”“:-1}”) 如果真结束 返回 (返回数据) ' ============================================================ ' 底层:生成签名 ' ============================================================ .子程序 生成签名, 文本型 .参数 参数字符串, 文本型 .局部变量 签名源, 文本型 ' 去除需要排除的字段后拼上 appkey 签名源 = 参数字符串 + 全局_应用密钥 返回 (取数据摘要 (到字节集 (签名源))) ' ============================================================ ' 底层:RC4 加密(返回十六进制) ' ============================================================ .子程序 RC4加密, 文本型 .参数 明文, 文本型 .参数 密钥, 文本型 .局部变量 S, 整数型, , "256" .局部变量 i, 整数型 .局部变量 j, 整数型 .局部变量 临时, 整数型 .局部变量 密钥长度, 整数型 .局部变量 密文, 文本型 .局部变量 字节值, 整数型 .局部变量 密钥字节, 整数型 密钥长度 = 取文本长度 (密钥) 如果真 (密钥长度 = 0) 返回 (“”) 如果真结束 .计次循环首 (256, i) S [i] = i - 1 .计次循环尾 () j = 0 .计次循环首 (256, i) 密钥字节 = 取代码 (密钥, (i - 1) % 密钥长度 + 1) 如果真 (密钥字节 < 0) 密钥字节 = 密钥字节 + 256 如果真结束 j = (j + S [i] + 密钥字节) % 256 临时 = S [i] S [i] = S [j + 1] S [j + 1] = 临时 .计次循环尾 () i = 0 j = 0 密文 = “” .局部变量 序号, 整数型, 参考 .计次循环首 (取文本长度 (明文), 序号) 字节值 = 取代码 (明文, 序号) 如果真 (字节值 < 0) 字节值 = 字节值 + 256 如果真结束 i = (i + 1) % 256 j = (j + S [i + 1]) % 256 临时 = S [i + 1] S [i + 1] = S [j + 1] S [j + 1] = 临时 密文 = 密文 + 取十六进制文本 (位异或 (字节值, S [(S [i + 1] + S [j + 1]) % 256 + 1])) .计次循环尾 () 返回 (密文) ' ============================================================ ' 底层:JSON 字段提取(极简) ' ============================================================ .子程序 解析_状态码, 整数型 .参数 响应, 文本型 .局部变量 位置, 整数型 .局部变量 值, 文本型 位置 = 寻找文本 (响应, #引号 + “code” + #引号 + “:”, , 假) 如果真 (位置 = -1) 返回 (-1) 如果真结束 位置 = 位置 + 取文本长度 (#引号 + “code” + #引号 + “:”) 值 = 取文本中间 (响应, 位置, 10) 值 = 取文本左边 (值, 寻找文本 (值, “,”, , 假) - 1) 返回 (到整数 (值)) .子程序 解析_消息, 文本型 .参数 响应, 文本型 .局部变量 位置, 整数型 .局部变量 起始, 整数型 .局部变量 结束, 整数型 位置 = 寻找文本 (响应, #引号 + “msg” + #引号 + “:” + #引号, , 假) 如果真 (位置 = -1) 返回 (“”) 如果真结束 起始 = 位置 + 取文本长度 (#引号 + “msg” + #引号 + “:” + #引号) 结束 = 寻找文本 (响应, #引号, 起始, 假) 返回 (取文本中间 (响应, 起始, 结束 - 起始)) .子程序 解析_字段, 文本型 .参数 响应, 文本型 .参数 字段名, 文本型 .局部变量 位置, 整数型 .局部变量 起始, 整数型 .局部变量 结束, 整数型 位置 = 寻找文本 (响应, #引号 + 字段名 + #引号 + “:” + #引号, , 假) 如果真 (位置 = -1) 返回 (“”) 如果真结束 起始 = 位置 + 取文本长度 (#引号 + 字段名 + #引号 + “:” + #引号) 结束 = 寻找文本 (响应, #引号, 起始, 假) 返回 (取文本中间 (响应, 起始, 结束 - 起始)) ' ============================================================ ' 底层:工具 ' ============================================================ .子程序 取随机文本, 文本型 .参数 长度, 整数型 .局部变量 字符集, 文本型 .局部变量 i, 整数型 .局部变量 结果, 文本型 .局部变量 位置, 整数型 字符集 = “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789” 结果 = “” .计次循环首 (长度, i) 位置 = 取随机数 (1, 取文本长度 (字符集)) 结果 = 结果 + 取文本中间 (字符集, 位置, 1) .计次循环尾 () 返回 (结果) .子程序 取十六进制文本, 文本型 .参数 数值, 整数型 .局部变量 高, 文本型 .局部变量 低, 文本型 .局部变量 字符表, 文本型 字符表 = “0123456789abcdef” 高 = 取文本中间 (字符表, 右移 (数值, 4) + 1, 1) 低 = 取文本中间 (字符表, 位与 (数值, 15) + 1, 1) 返回 (高 + 低) ' ============================================================ ' 编码说明(重要) ' ============================================================ ' 易语言的文本型本身就是 GBK 编码,而服务端 mi_rc4 会做 ' UTF-8 -> GBK 的转换,因此本 SDK 在 RC4 加密前需要: ' 1. 若你的参数是纯 ASCII(卡密、设备码通常都是)→ 无需处理 ' 2. 若参数含中文 → 必须先用「编码_gbk到utf8」逆转换, ' 因为服务端期望收到的是从 UTF-8 转成 GBK 的字节。 ' ' 具体做法:在调用 RC4加密 之前,把明文用 ' 编码_utf8到gbk (明文) ' 处理一次即可与服务端对齐。 ' ' 例: ' 请求体 = 编码_utf8到gbk (附加数据 + “&value=” + 随机值) ' data = 编码_URL编码 (RC4加密 (请求体, 全局_通信密钥)) ' ' ============================================================ ' 推荐:先用明文模式(加密类型=0)调通,再启用 RC4 ' ============================================================