ci: update Node.js requirement and improve code consistency

Updated the README to require Node.js 18+ and added Docker usage instructions. Refactored util/client-sign.js for consistent code style and improved variable naming. Fixed the login_cellphone module to use 'weapi' in createOption. Removed deprecated code from server.js and improved CORS header formatting. Minor fix in util/request.js for user agent selection.

Co-Authored-By: binaryify <binaryify@gmail.com>
This commit is contained in:
ElyPrism 2026-01-16 22:35:16 +08:00
parent 5fc9346e0e
commit 805d0bccc5
No known key found for this signature in database
6 changed files with 213 additions and 180 deletions

View File

@ -22,7 +22,7 @@
## 环境要求
需要 NodeJS 14+ 环境
需要 NodeJS 18+ 环境
## 安装
@ -70,6 +70,45 @@ npx NeteaseCloudMusicApi@latest
使用此命令,可直接启动服务,无需下载或者 clone 项目
## Docker 容器运行
> 注意: 在 docker 中运行的时候, 由于使用了 request 来发请求, 所以会检查几个 proxy 相关的环境变量(如下所列), 这些环境变量 会影响到 request 的代理, 详情请参考[request 的文档](https://github.com/request/request#proxies), 如果这些环境变量 指向的代理不可用, 那么就会造成错误, 所以在使用 docker 的时候一定要注意这些环境变量. 不过, 要是你在 query 中加上了 proxy 参数, 那么环境变量会被覆盖, 就会用你通过 proxy 参数提供的代理了.
request 相关的环境变量
1. http_proxy
2. https_proxy
3. HTTP_PROXY
4. HTTPS_PROXY
5. no_proxy
6. NO_PROXY
```shell
docker pull binaryify/netease_cloud_music_api
docker run -d -p 3000:3000 --name netease_cloud_music_api binaryify/netease_cloud_music_api
// 或者
docker run -d -p 3000:3000 binaryify/netease_cloud_music_api
// 去掉或者设置相关的环境变量
docker run -d -p 3000:3000 --name netease_cloud_music_api -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= binaryify/netease_cloud_music_api
// 或者
docker run -d -p 3000:3000 -e http_proxy= -e https_proxy= -e no_proxy= -e HTTP_PROXY= -e HTTPS_PROXY= -e NO_PROXY= binaryify/netease_cloud_music_api
```
> 以下是自行 build docker 镜像方式
```
$ git clone https://gitlab.com/Binaryify/neteasecloudmusicapi.git && cd NeteaseCloudMusicApi
$ sudo docker build . -t netease-music-api
$ sudo docker run -d -p 3000:3000 netease-music-api
## Vercel 部署
v4.0.8 加入了 Vercel 配置文件,可以直接在 Vercel 下部署了,不需要自己的服务器

View File

@ -18,7 +18,7 @@ module.exports = async (query, request) => {
let result = await request(
`/api/w/login/cellphone`,
data,
createOption(query),
createOption(query, 'weapi'),
)
if (result.body.code === 200) {

View File

@ -1,6 +1,6 @@
{
"name": "NeteaseCloudMusicApi",
"version": "4.28.0",
"version": "4.28.1",
"description": "网易云音乐 NodeJS 版 API",
"scripts": {
"start": "node app.js",
@ -69,11 +69,11 @@
"axios": "^1.13.2",
"crypto-js": "^4.2.0",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"express": "^4.22.1",
"express-fileupload": "^1.5.2",
"md5": "^2.3.0",
"music-metadata": "^7.14.0",
"node-forge": "^1.3.1",
"node-forge": "^1.3.3",
"pac-proxy-agent": "^7.2.0",
"qrcode": "^1.5.4",
"safe-decode-uri-component": "^1.2.1",

217
pnpm-lock.yaml generated
View File

@ -21,8 +21,8 @@ importers:
specifier: ^17.2.3
version: 17.2.3
express:
specifier: ^4.21.2
version: 4.21.2
specifier: ^4.22.1
version: 4.22.1
express-fileupload:
specifier: ^1.5.2
version: 1.5.2
@ -33,8 +33,8 @@ importers:
specifier: ^7.14.0
version: 7.14.0
node-forge:
specifier: ^1.3.1
version: 1.3.1
specifier: ^1.3.3
version: 1.3.3
pac-proxy-agent:
specifier: ^7.2.0
version: 7.2.0
@ -188,8 +188,8 @@ packages:
'@types/express-fileupload@1.5.1':
resolution: {integrity: sha512-DllImBVI1lCyjl2klky/TEwk60mbNebgXv1669h66g9TfptWSrEFq5a/raHSutaFzjSm1tmn9ypdNfu4jPSixQ==}
'@types/express-serve-static-core@4.19.7':
resolution: {integrity: sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==}
'@types/express-serve-static-core@4.19.8':
resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==}
'@types/express@4.17.25':
resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==}
@ -421,8 +421,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
basic-ftp@5.0.5:
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
basic-ftp@5.1.0:
resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==}
engines: {node: '>=10.0.0'}
binary-extensions@2.3.0:
@ -432,8 +432,8 @@ packages:
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
body-parser@1.20.3:
resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
body-parser@1.20.4:
resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
brace-expansion@1.1.12:
@ -580,11 +580,11 @@ packages:
convert-source-map@1.9.0:
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
cookie-signature@1.0.6:
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
cookie-signature@1.0.7:
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
cookie@0.7.1:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
cookie@0.7.2:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
core-js@2.6.12:
@ -767,10 +767,6 @@ packages:
empower@1.3.1:
resolution: {integrity: sha512-uB6/ViBaawOO/uujFADTK3SqdYlxYNn+N4usK9MRKZ4Hbn/1QSy8k2PezxCA2/+JGbF8vd/eOfghZ90oOSDZCA==}
encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
@ -782,8 +778,8 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
es-abstract@1.24.0:
resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==}
es-abstract@1.24.1:
resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
engines: {node: '>= 0.4'}
es-define-property@1.0.1:
@ -942,8 +938,8 @@ packages:
espurify@1.8.1:
resolution: {integrity: sha512-ZDko6eY/o+D/gHCWyHTU85mKDgYcS4FJj7S+YD6WIInm7GQ6AnOjmcL4+buFV/JOztVLELi/7MmuGU5NHta0Mg==}
esquery@1.6.0:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
esquery@1.7.0:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'}
esrecurse@4.3.0:
@ -989,8 +985,8 @@ packages:
resolution: {integrity: sha512-wxUJn2vTHvj/kZCVmc5/bJO15C7aSMyHeuXYY3geKpeKibaAoQGcEv5+sM6nHS2T7VF+QHS4hTWPiY2mKofEdg==}
engines: {node: '>=12.0.0'}
express@4.21.2:
resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}
express@4.22.1:
resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==}
engines: {node: '>= 0.10.0'}
ext@1.7.0:
@ -1019,8 +1015,8 @@ packages:
fast-safe-stringify@2.1.1:
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@ -1034,8 +1030,8 @@ packages:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
finalhandler@1.3.1:
resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
finalhandler@1.3.2:
resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==}
engines: {node: '>= 0.8'}
find-up@4.1.0:
@ -1073,8 +1069,8 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
form-data@4.0.4:
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
forwarded@0.2.0:
@ -1224,8 +1220,8 @@ packages:
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
http-errors@2.0.1:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
http-proxy-agent@7.0.2:
@ -1651,8 +1647,8 @@ packages:
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-abi@3.85.0:
resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==}
node-abi@3.86.0:
resolution: {integrity: sha512-sn9Et4N3ynsetj3spsZR729DVlGH6iBG4RiDMV7HEp3guyOW6W3S0unGpLDxT50mXortGUMax/ykUNQXdqc/Xg==}
engines: {node: '>=10'}
node-fetch@2.7.0:
@ -1664,8 +1660,8 @@ packages:
encoding:
optional: true
node-forge@1.3.1:
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
node-forge@1.3.3:
resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==}
engines: {node: '>= 6.13.0'}
node-windows@1.0.0-beta.8:
@ -1876,8 +1872,8 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier-linter-helpers@1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
prettier-linter-helpers@1.0.1:
resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==}
engines: {node: '>=6.0.0'}
prettier@2.7.1:
@ -1918,8 +1914,8 @@ packages:
engines: {node: '>=10.13.0'}
hasBin: true
qs@6.13.0:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
qs@6.14.1:
resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==}
engines: {node: '>=0.6'}
queue-microtask@1.2.3:
@ -1935,8 +1931,8 @@ packages:
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
engines: {node: '>= 0.6'}
raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
raw-body@2.5.3:
resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==}
engines: {node: '>= 0.8'}
rc@1.2.8:
@ -2036,8 +2032,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sax@1.4.3:
resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==}
sax@1.4.4:
resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==}
engines: {node: '>=11.0.0'}
secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
@ -2047,15 +2044,15 @@ packages:
engines: {node: '>=10'}
hasBin: true
send@0.19.0:
resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
send@0.19.2:
resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==}
engines: {node: '>= 0.8.0'}
serialize-javascript@6.0.0:
resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==}
serve-static@1.16.2:
resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
serve-static@1.16.3:
resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==}
engines: {node: '>= 0.8.0'}
set-blocking@2.0.0:
@ -2162,8 +2159,8 @@ packages:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
statuses@2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
statuses@2.0.2:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
stop-iteration-iterator@1.1.0:
@ -2416,8 +2413,8 @@ packages:
which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
which-typed-array@1.1.19:
resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
which-typed-array@1.1.20:
resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==}
engines: {node: '>= 0.4'}
which@2.0.2:
@ -2571,7 +2568,7 @@ snapshots:
'@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
fastq: 1.20.1
'@tokenizer/token@0.3.0': {}
@ -2595,7 +2592,7 @@ snapshots:
'@types/busboy': 1.5.4
'@types/express': 4.17.25
'@types/express-serve-static-core@4.19.7':
'@types/express-serve-static-core@4.19.8':
dependencies:
'@types/node': 16.11.19
'@types/qs': 6.14.0
@ -2605,7 +2602,7 @@ snapshots:
'@types/express@4.17.25':
dependencies:
'@types/body-parser': 1.19.6
'@types/express-serve-static-core': 4.19.7
'@types/express-serve-static-core': 4.19.8
'@types/qs': 6.14.0
'@types/serve-static': 1.15.10
@ -2807,7 +2804,7 @@ snapshots:
array-buffer-byte-length: 1.0.2
call-bind: 1.0.8
define-properties: 1.2.1
es-abstract: 1.24.0
es-abstract: 1.24.1
es-errors: 1.3.0
get-intrinsic: 1.3.0
is-array-buffer: 3.0.5
@ -2833,7 +2830,7 @@ snapshots:
axios@1.13.2:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.4
form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
@ -2842,7 +2839,7 @@ snapshots:
base64-js@1.5.1: {}
basic-ftp@5.0.5: {}
basic-ftp@5.1.0: {}
binary-extensions@2.3.0: {}
@ -2852,18 +2849,18 @@ snapshots:
inherits: 2.0.4
readable-stream: 3.6.2
body-parser@1.20.3:
body-parser@1.20.4:
dependencies:
bytes: 3.1.2
content-type: 1.0.5
debug: 2.6.9
depd: 2.0.0
destroy: 1.2.0
http-errors: 2.0.0
http-errors: 2.0.1
iconv-lite: 0.4.24
on-finished: 2.4.1
qs: 6.13.0
raw-body: 2.5.2
qs: 6.14.1
raw-body: 2.5.3
type-is: 1.6.18
unpipe: 1.0.0
transitivePeerDependencies:
@ -3025,9 +3022,9 @@ snapshots:
convert-source-map@1.9.0: {}
cookie-signature@1.0.6: {}
cookie-signature@1.0.7: {}
cookie@0.7.1: {}
cookie@0.7.2: {}
core-js@2.6.12: {}
@ -3202,8 +3199,6 @@ snapshots:
core-js: 2.6.12
empower-core: 1.2.0
encodeurl@1.0.2: {}
encodeurl@2.0.0: {}
end-of-stream@1.4.5:
@ -3212,7 +3207,7 @@ snapshots:
entities@4.5.0: {}
es-abstract@1.24.0:
es-abstract@1.24.1:
dependencies:
array-buffer-byte-length: 1.0.2
arraybuffer.prototype.slice: 1.0.4
@ -3267,7 +3262,7 @@ snapshots:
typed-array-byte-offset: 1.0.4
typed-array-length: 1.0.7
unbox-primitive: 1.1.0
which-typed-array: 1.1.19
which-typed-array: 1.1.20
es-define-property@1.0.1: {}
@ -3382,7 +3377,7 @@ snapshots:
dependencies:
eslint: 8.7.0
prettier: 2.7.1
prettier-linter-helpers: 1.0.0
prettier-linter-helpers: 1.0.1
optionalDependencies:
eslint-config-prettier: 8.5.0(eslint@8.7.0)
@ -3419,7 +3414,7 @@ snapshots:
eslint-utils: 3.0.0(eslint@8.7.0)
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.6.0
esquery: 1.7.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
@ -3507,7 +3502,7 @@ snapshots:
dependencies:
core-js: 2.6.12
esquery@1.6.0:
esquery@1.7.0:
dependencies:
estraverse: 5.3.0
@ -3550,36 +3545,36 @@ snapshots:
dependencies:
busboy: 1.6.0
express@4.21.2:
express@4.22.1:
dependencies:
accepts: 1.3.8
array-flatten: 1.1.1
body-parser: 1.20.3
body-parser: 1.20.4
content-disposition: 0.5.4
content-type: 1.0.5
cookie: 0.7.1
cookie-signature: 1.0.6
cookie: 0.7.2
cookie-signature: 1.0.7
debug: 2.6.9
depd: 2.0.0
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
finalhandler: 1.3.1
finalhandler: 1.3.2
fresh: 0.5.2
http-errors: 2.0.0
http-errors: 2.0.1
merge-descriptors: 1.0.3
methods: 1.1.2
on-finished: 2.4.1
parseurl: 1.3.3
path-to-regexp: 0.1.12
proxy-addr: 2.0.7
qs: 6.13.0
qs: 6.14.1
range-parser: 1.2.1
safe-buffer: 5.2.1
send: 0.19.0
serve-static: 1.16.2
send: 0.19.2
serve-static: 1.16.3
setprototypeof: 1.2.0
statuses: 2.0.1
statuses: 2.0.2
type-is: 1.6.18
utils-merge: 1.0.1
vary: 1.1.2
@ -3610,7 +3605,7 @@ snapshots:
fast-safe-stringify@2.1.1: {}
fastq@1.19.1:
fastq@1.20.1:
dependencies:
reusify: 1.1.0
@ -3628,14 +3623,14 @@ snapshots:
dependencies:
to-regex-range: 5.0.1
finalhandler@1.3.1:
finalhandler@1.3.2:
dependencies:
debug: 2.6.9
encodeurl: 2.0.0
escape-html: 1.0.3
on-finished: 2.4.1
parseurl: 1.3.3
statuses: 2.0.1
statuses: 2.0.2
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
@ -3668,7 +3663,7 @@ snapshots:
dependencies:
is-callable: 1.2.7
form-data@4.0.4:
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
@ -3746,7 +3741,7 @@ snapshots:
get-uri@6.0.5:
dependencies:
basic-ftp: 5.0.5
basic-ftp: 5.1.0
data-uri-to-buffer: 6.0.2
debug: 4.4.3(supports-color@9.4.0)
transitivePeerDependencies:
@ -3837,12 +3832,12 @@ snapshots:
domutils: 3.2.2
entities: 4.5.0
http-errors@2.0.0:
http-errors@2.0.1:
dependencies:
depd: 2.0.0
inherits: 2.0.4
setprototypeof: 1.2.0
statuses: 2.0.1
statuses: 2.0.2
toidentifier: 1.0.1
http-proxy-agent@7.0.2:
@ -4035,7 +4030,7 @@ snapshots:
is-typed-array@1.1.15:
dependencies:
which-typed-array: 1.1.19
which-typed-array: 1.1.20
is-unicode-supported@0.1.0: {}
@ -4270,7 +4265,7 @@ snapshots:
next-tick@1.1.0: {}
node-abi@3.85.0:
node-abi@3.86.0:
dependencies:
semver: 7.7.3
@ -4278,7 +4273,7 @@ snapshots:
dependencies:
whatwg-url: 5.0.0
node-forge@1.3.1: {}
node-forge@1.3.3: {}
node-windows@1.0.0-beta.8:
dependencies:
@ -4556,7 +4551,7 @@ snapshots:
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 1.0.2
node-abi: 3.85.0
node-abi: 3.86.0
pump: 3.0.3
rc: 1.2.8
simple-get: 4.0.1
@ -4567,7 +4562,7 @@ snapshots:
prelude-ls@1.2.1: {}
prettier-linter-helpers@1.0.0:
prettier-linter-helpers@1.0.1:
dependencies:
fast-diff: 1.3.0
@ -4601,7 +4596,7 @@ snapshots:
pngjs: 5.0.0
yargs: 15.4.1
qs@6.13.0:
qs@6.14.1:
dependencies:
side-channel: 1.1.0
@ -4615,10 +4610,10 @@ snapshots:
range-parser@1.2.1: {}
raw-body@2.5.2:
raw-body@2.5.3:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
http-errors: 2.0.1
iconv-lite: 0.4.24
unpipe: 1.0.0
@ -4665,7 +4660,7 @@ snapshots:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
es-abstract: 1.24.0
es-abstract: 1.24.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
get-intrinsic: 1.3.0
@ -4743,27 +4738,27 @@ snapshots:
safer-buffer@2.1.2: {}
sax@1.4.3: {}
sax@1.4.4: {}
secure-json-parse@2.7.0: {}
semver@7.7.3: {}
send@0.19.0:
send@0.19.2:
dependencies:
debug: 2.6.9
depd: 2.0.0
destroy: 1.2.0
encodeurl: 1.0.2
encodeurl: 2.0.0
escape-html: 1.0.3
etag: 1.8.1
fresh: 0.5.2
http-errors: 2.0.0
http-errors: 2.0.1
mime: 1.6.0
ms: 2.1.3
on-finished: 2.4.1
range-parser: 1.2.1
statuses: 2.0.1
statuses: 2.0.2
transitivePeerDependencies:
- supports-color
@ -4771,12 +4766,12 @@ snapshots:
dependencies:
randombytes: 2.1.0
serve-static@1.16.2:
serve-static@1.16.3:
dependencies:
encodeurl: 2.0.0
escape-html: 1.0.3
parseurl: 1.3.3
send: 0.19.0
send: 0.19.2
transitivePeerDependencies:
- supports-color
@ -4908,7 +4903,7 @@ snapshots:
split2@4.2.0: {}
statuses@2.0.1: {}
statuses@2.0.2: {}
stop-iteration-iterator@1.1.0:
dependencies:
@ -4943,7 +4938,7 @@ snapshots:
call-bound: 1.0.4
define-data-property: 1.1.4
define-properties: 1.2.1
es-abstract: 1.24.0
es-abstract: 1.24.1
es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2
@ -5047,7 +5042,7 @@ snapshots:
dependencies:
gopd: 1.2.0
typedarray.prototype.slice: 1.0.5
which-typed-array: 1.1.19
which-typed-array: 1.1.20
tslib@1.14.1: {}
@ -5122,7 +5117,7 @@ snapshots:
dependencies:
call-bind: 1.0.8
define-properties: 1.2.1
es-abstract: 1.24.0
es-abstract: 1.24.1
es-errors: 1.3.0
get-proto: 1.0.1
math-intrinsics: 1.1.0
@ -5189,7 +5184,7 @@ snapshots:
isarray: 2.0.5
which-boxed-primitive: 1.1.1
which-collection: 1.0.2
which-typed-array: 1.1.19
which-typed-array: 1.1.20
which-collection@1.0.2:
dependencies:
@ -5200,7 +5195,7 @@ snapshots:
which-module@2.0.1: {}
which-typed-array@1.1.19:
which-typed-array@1.1.20:
dependencies:
available-typed-arrays: 1.0.7
call-bind: 1.0.8
@ -5234,7 +5229,7 @@ snapshots:
xml2js@0.6.2:
dependencies:
sax: 1.4.3
sax: 1.4.4
xmlbuilder: 11.0.1
xml@1.0.1: {}

View File

@ -1,5 +1,5 @@
const crypto = require("crypto");
const os = require("os");
const crypto = require('crypto')
const os = require('os')
class AdvancedClientSignGenerator {
/**
@ -7,25 +7,25 @@ class AdvancedClientSignGenerator {
*/
static getRealMacAddress() {
try {
const interfaces = os.networkInterfaces();
const interfaces = os.networkInterfaces()
for (let interfaceName in interfaces) {
const interface = interfaces[interfaceName];
for (let i = 0; i < interface.length; i++) {
const alias = interface[i];
const interfaceItem = interfaces[interfaceName]
for (let i = 0; i < interfaceItem.length; i++) {
const alias = interfaceItem[i]
// 排除内部地址和无效地址
if (
alias.mac &&
alias.mac !== "00:00:00:00:00:00" &&
alias.mac !== '00:00:00:00:00:00' &&
!alias.internal
) {
return alias.mac.toUpperCase();
return alias.mac.toUpperCase()
}
}
}
return null;
return null
} catch (error) {
console.warn("获取MAC地址失败:", error.message);
return null;
console.warn('获取MAC地址失败:', error.message)
return null
}
}
@ -33,108 +33,108 @@ class AdvancedClientSignGenerator {
* 生成随机MAC地址
*/
static generateRandomMac() {
const chars = "0123456789ABCDEF";
let mac = "";
const chars = '0123456789ABCDEF'
let mac = ''
for (let i = 0; i < 6; i++) {
if (i > 0) mac += ":";
if (i > 0) mac += ':'
mac +=
chars[Math.floor(Math.random() * 16)] +
chars[Math.floor(Math.random() * 16)];
chars[Math.floor(Math.random() * 16)]
}
// 确保第一个字节是单播地址最低位为0
const firstByte = parseInt(mac.substring(0, 2), 16);
const firstByte = parseInt(mac.substring(0, 2), 16)
const unicastFirstByte = (firstByte & 0xfe)
.toString(16)
.padStart(2, "0")
.toUpperCase();
return unicastFirstByte + mac.substring(2);
.padStart(2, '0')
.toUpperCase()
return unicastFirstByte + mac.substring(2)
}
/**
* 获取MAC地址优先真实否则随机
*/
static getMacAddress() {
const realMac = this.getRealMacAddress();
const realMac = this.getRealMacAddress()
if (realMac) {
return realMac;
return realMac
}
console.warn("无法获取真实MAC地址使用随机生成");
return this.generateRandomMac();
console.warn('无法获取真实MAC地址使用随机生成')
return this.generateRandomMac()
}
/**
* 字符串转HEX编码
*/
static stringToHex(str) {
return Buffer.from(str, "utf8").toString("hex").toUpperCase();
return Buffer.from(str, 'utf8').toString('hex').toUpperCase()
}
/**
* SHA-256哈希
*/
static sha256(data) {
return crypto.createHash("sha256").update(data, "utf8").digest("hex");
return crypto.createHash('sha256').update(data, 'utf8').digest('hex')
}
/**
* 生成随机设备ID
*/
static generateRandomDeviceId() {
const partLengths = [4, 4, 4, 4, 4, 4, 4, 5]; // 各部分长度
const chars = "0123456789ABCDEF";
const partLengths = [4, 4, 4, 4, 4, 4, 4, 5] // 各部分长度
const chars = '0123456789ABCDEF'
const parts = partLengths.map((length) => {
let part = "";
let part = ''
for (let i = 0; i < length; i++) {
part += chars[Math.floor(Math.random() * 16)];
part += chars[Math.floor(Math.random() * 16)]
}
return part;
});
return part
})
return parts.join("_");
return parts.join('_')
}
/**
* 生成随机clientSign优先使用真实MAC否则随机
*/
static generateRandomClientSign(secretKey = "") {
static generateRandomClientSign(secretKey = '') {
// 获取MAC地址优先真实否则随机
const macAddress = this.getMacAddress();
const macAddress = this.getMacAddress()
// 生成随机设备ID
const deviceId = this.generateRandomDeviceId();
const deviceId = this.generateRandomDeviceId()
// 转换设备ID为HEX
const hexDeviceId = this.stringToHex(deviceId);
const hexDeviceId = this.stringToHex(deviceId)
// 构造签名字符串
const signString = `${macAddress}@@@${hexDeviceId}`;
const signString = `${macAddress}@@@${hexDeviceId}`
// 生成哈希
const hash = this.sha256(signString + secretKey);
const hash = this.sha256(signString + secretKey)
return `${signString}@@@@@@${hash}`;
return `${signString}@@@@@@${hash}`
}
/**
* 批量生成多个随机签名
*/
static generateMultipleRandomSigns(count, secretKey = "") {
const signs = [];
static generateMultipleRandomSigns(count, secretKey = '') {
const signs = []
for (let i = 0; i < count; i++) {
signs.push(this.generateRandomClientSign(secretKey));
signs.push(this.generateRandomClientSign(secretKey))
}
return signs;
return signs
}
/**
* 使用指定参数生成签名
*/
static generateWithCustomDeviceId(macAddress, deviceId, secretKey = "") {
const hexDeviceId = this.stringToHex(deviceId);
const signString = `${macAddress}@@@${hexDeviceId}`;
const hash = this.sha256(signString + secretKey);
return `${signString}@@@@@@${hash}`;
static generateWithCustomDeviceId(macAddress, deviceId, secretKey = '') {
const hexDeviceId = this.stringToHex(deviceId)
const signString = `${macAddress}@@@${hexDeviceId}`
const hash = this.sha256(signString + secretKey)
return `${signString}@@@@@@${hash}`
}
/**
@ -142,28 +142,28 @@ class AdvancedClientSignGenerator {
*/
static validateClientSign(clientSign) {
try {
const parts = clientSign.split("@@@@@@");
if (parts.length !== 2) return false;
const parts = clientSign.split('@@@@@@')
if (parts.length !== 2) return false
const [infoPart, hash] = parts;
const infoParts = infoPart.split("@@@");
if (infoParts.length !== 2) return false;
const [infoPart, hash] = parts
const infoParts = infoPart.split('@@@')
if (infoParts.length !== 2) return false
const [mac, hexDeviceId] = infoParts;
const [mac, hexDeviceId] = infoParts
// 验证MAC地址格式
const macRegex = /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/;
if (!macRegex.test(mac)) return false;
const macRegex = /^([0-9A-F]{2}:){5}[0-9A-F]{2}$/
if (!macRegex.test(mac)) return false
// 验证哈希格式
const hashRegex = /^[0-9a-f]{64}$/;
if (!hashRegex.test(hash)) return false;
const hashRegex = /^[0-9a-f]{64}$/
if (!hashRegex.test(hash)) return false
return true;
return true
} catch (error) {
return false;
return false
}
}
}
module.exports = AdvancedClientSignGenerator;
module.exports = AdvancedClientSignGenerator

View File

@ -100,7 +100,7 @@ const SPECIAL_STATUS_CODES = new Set([201, 302, 400, 502, 800, 801, 802, 803])
// chooseUserAgent函数
const chooseUserAgent = (crypto, uaType = 'pc') => {
return userAgentMap[crypto]?.[uaType] || ''
return (userAgentMap[crypto] && userAgentMap[crypto][uaType]) || ''
}
// cookie处理
@ -152,8 +152,7 @@ const createHeaderCookie = (header) => {
const generateRequestId = () => {
return `${now()}_${floor(random() * 1000)
.toString()
.padStart(4, "0")}`;
.padStart(4, '0')}`
}
const createRequest = (uri, data, options) => {