feat: Add xeapi Aegis support#175
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| * @param {string} input - XOR 编码后的 base64 输入 | ||
| * @returns {Buffer} 解码后的原始字节 | ||
| */ | ||
| function xorDecode(input) { |
There was a problem hiding this comment.
Code Review
This pull request implements the xeapi (Aegis) encryption scheme, which involves a three-layer encryption process (AES-256-GCM, ECDH P-256, and HKDF-SHA256) reverse-engineered from the Netease Cloud Music Android app. The changes include detailed documentation of the algorithm, a new utility for encryption/decryption, integration into the core request logic, and a new VIP tasks endpoint. Feedback from the reviewer highlights a compatibility issue with Node.js versions regarding crypto.hkdfSync, an invalid hex string length for the static AES key, and the use of placeholder values for the HKDF salt that will prevent successful server communication. Additionally, the reviewer suggested improving error handling for missing public keys and adopting modern JavaScript scoping practices.
| const sharedSecret = ecdh.computeSecret(serverPublicKey) | ||
|
|
||
| // HKDF-SHA256 派生 | ||
| const derivedKey = crypto.hkdfSync( |
There was a problem hiding this comment.
| } | ||
|
|
||
| // 参考值 (issue.md 提供, 可能不完整) | ||
| const keyHex = 'b31d1a4bf2ba849fe97edd55727d896dc1ed9ee492c0e86947c6dfb93b1' |
| if (!serverPublicKeyBase64) { | ||
| console.warn( | ||
| '[xeapi] ⚠️ 服务器公钥为空,使用临时密钥占位 (此加密无法被真实服务器解密)', | ||
| ) | ||
| const tempEcdh = crypto.createECDH('prime256v1') | ||
| tempEcdh.generateKeys() | ||
| serverPublicKeyBase64 = tempEcdh | ||
| .getPublicKey(null, 'compressed') | ||
| .toString('base64') | ||
| } |
There was a problem hiding this comment.
Generating a random ECC key pair when the server public key is missing will result in an encrypted payload that the server cannot decrypt, leading to a failed request. It is better to throw an error early to inform the user that a valid serverPublicKey is required for xeapi encryption.
if (!serverPublicKeyBase64) {
throw new Error('[xeapi] 服务器公钥未设置!xeapi 加密需要有效的服务器 ECC 公钥。')
}| options.xeapiServerKey || process.env.XEAPI_SERVER_PUBLIC_KEY || '', | ||
| }) | ||
| encryptData = xeapiResult.params // { B, S, R } | ||
| var xeapiDynamicKey = xeapiResult.dynamicKey // 用于响应解密 |
There was a problem hiding this comment.
The variable xeapiDynamicKey is declared with var inside a switch case. While this works due to function-level hoisting (allowing it to be accessed in the .then block later), it is considered poor practice in modern JavaScript. It is recommended to declare the variable using let at the top of the createRequest function scope to improve clarity and avoid potential hoisting-related bugs.
| * 🟡 待从 libAegisSDK.so DAT_001a04c0 提取 (Ghidra read_memory) | ||
| * 这是一个 16 字节的全局数据,目前使用占位符 | ||
| */ | ||
| const HKDF_SALT = Buffer.alloc(16, 0) |
There was a problem hiding this comment.
由于缺少AES密钥和ECC公钥, 这个PR随时可能关闭