首页
留言
动态
归档
推荐
音乐
工具
Search
1
Emby公益服-上万部电影电视剧免费看
62,710 阅读
2
openwrt-docker部署lxk0301京东自动签到脚本
12,596 阅读
3
QuantumultX-京东签到撸京东豆
10,969 阅读
4
LXK0301京东签到脚本-自动提交互助码
9,356 阅读
5
微信-域名被封监测以及自动更换被封域名
9,022 阅读
随便写写
科学上网
Web开发
瞎折腾
Search
标签搜索
quantumultx
laravel
openwrt
laravel nova
laradock
telegram
薅羊毛
google adsense
jd_scripts
京东签到
ubuntu
oh-my-zsh
web开发环境
nginx
工具
shadowsocks shadowsocksR
RBAC
权限管理
内网穿透
Python
orzlee
累计撰写
44
篇文章
累计收到
595
条评论
首页
栏目
随便写写
科学上网
Web开发
瞎折腾
页面
留言
动态
归档
推荐
音乐
工具
搜索到
2
篇与
jd_scripts
的结果
openwrt-通过telegram bot自动创建启动jd-scripts docker容器
2021年03月13日
2,625 阅读
8 评论
0 点赞
2021-03-13
前言 使用lxk0301大佬的jd_scripts-docker脚本后突发奇想,如果利用telegram bot获取用户京东cookie,然后自动创建docker容器并且启动容器跑脚本,这个流程一气呵成,以后京东cookie过期就可以很方便的处理,然后自己朋友也可以扫京东登陆二维码就部署整个签到脚本了。 在openwrt折腾可以看我之前的文章:openwrt-docker部署lxk0301京东自动签到脚本 2021-03-22更新:作者已经更新docker容器,详细说明:增加bot交互,spnode指令(jd_docker仓库被Gitee封了,最新地址jd_docker)。容器已经自带telegram bot,大量与docker容器配套的命令以及获取cookie功能。有兴趣可以玩玩看。 运行环境和思路 我使用的是openwrt软路由(CPU J4105, 8G, 128G SSD),由于性能过剩,不折腾点东西不舒服,所以没有放VPS上。软路由固件使用的是eSir大佬的高大全版本,eSir大佬固件盘。记得扩容overlay分区,然后opt容量也要注意下,我在openwrt-docker部署lxk0301京东自动签到脚本文章中提到过。 由于部署在路由器上,telegram bot webhook发到路由可能会遇到GFW的干扰(不确定是否会干扰入境流量,可以试试看),我使用frp(eSir openwrt自带)做内网穿透,frp服务端需挂在境外服务器上,这样外网问题就能解决。但是路由器还是需要科学上网的。 telegram bot开发使用python,还有少部分lua,因为openwrt上的dockerman插件语言也是lua语言,启动docker时还是希望能在dockerman中管理,所以还是折腾了lua。 整个流程: 用户在telegram bot发送命令 telegram bot返回一个京东登陆二维码(以下图片中的login命令是测试时候的) 用户扫码二维码,服务器获取用户京东cookie 服务器拿到cookie创建(或删除重建)一个jd_scripts-docker容器,并且启动 提示用户启动成功或失败 成功后可以在openwrt web端docker-容器看到新加入的用户docker容器,还可以在openwrt的dockerman插件中管理容器。 思路: 用户发送命令给telegram bot,服务器接收到后进入配置好的容器,执行/scripts/getJDCookies.js脚本获取脚本生成的京东登陆链接,用链接生成二维码,通过telegram bot返回给用户。二维码有效期三分钟,脚本也会持续三分钟。用户扫码后服务器会捕获到脚本回显,提取京东cookie。 拿到cooki后判断用户是否已经创建容器,创建了多久,超过N天的删除旧容器,然后再创建一个新的容器启动,没有使用过的用户直接创建一个新的。由于我想兼容dockerman,所以用lua语言折腾了一个简版创建和管理docker命令行脚本。懒得折腾了,服务器直接复制一份已存在的jd_scripts-docker脚本配置新建,环境变量和脚本可以自行配置就行了。启动成功捕获命令行回显容器ID,容器ID和用户信息,京东cookie存Sqlite数据库。 由于防止用户频繁提交,使用reids存下已经获取二维码的telegram用户ID,必须等待三分钟或者jd_scripts-docker成功后再次获取。 本来是想使用一个容器,然后在容器里面修改JDCOOKIE环境变量,配置多个cookie。但是目前有两个缺点: 单容器多用户跑脚本时会一个个跑,并不是并发跑,人数一多脚本执行时间会很长(如果限制单容器用户人数也许是个办法,比如说一个容器只允许5个用户,多出来的再建个新容器,以后再说吧!)。 脚本通知(多账号)只能发给一个环境变量配置好的接收用户。 不过最近lxk0301大佬更新了单容器多用户脚本会自动互助的功能,只能自己再想办法折腾下了。 脚本说明: 2021-03-16更新:添加单容器追加cookie功能,这样VPS应该能用了(我没有测试,但是不涉及到dockerman容器管理应该是没有问题的!): 仓库地址:Github env.config文件添加两个配置,主要是add_user_mode添加用户模式,默认是create,单容器是attach: [telegram_bot] ... [jd_scripts] ... auto_delete_docker_by_days=30 //目前没有实现自动删除过期用户容器功能,只是attach模式中过滤超过N天的用户cookie add_user_mode=attach //创建容易方式:attach 附加,create 创建,附加只会追加cookie到existed_docker_container_name配置容器里,create每一个用户都会创建一个新的docker容器 [sqlite] ... 如果使用attach模式,会在当前目录生成一个cookies.sh文件,执行该文件会导入所有通过telegram bot加入的有效用户cookie到环境变量。 使用attach模式方法: 现在开始准备新建一个容器,挂载cookies.sh文件到jd_scripts_docker容器(export_jd_cookies_script_orz.sh挂载文件名要改的话下面的脚本内容也要跟着修改): 你的目录/cookies.sh:/scripts/docker/export_jd_cookies_script_orz.sh 添加一个自定义脚本: 先挂载本地脚本(名称目录自定,但是挂载后的不要改了,不然又要改脚本内容。如果远程脚本就不用挂载了): 你的目录/docker_shell.sh:/scripts/docker/docker_shell.sh 添加环境变量(远程脚本不用上面的挂载docker_shell.sh步骤): CUSTOM_SHELL_FILE=/scripts/docker/docker_shell.sh 脚本内容,意思是每分钟执行update_crontab.sh脚本: if ! [ ! -f "/scripts/docker/export_jd_cookies_script_orz.sh" ]; then echo "* * * * * sh +x /scripts/docker/update_crontab.sh 2>&1" >> /scripts/docker/merged_list_file.sh fi 挂载update_crontab.sh脚本 你的目录/update_crontab.sh:/scripts/docker/update_crontab.sh 脚本内容: FIND_FILE="/scripts/docker/merged_list_file.sh" FIND_STR="export_jd_cookies_script_orz.sh" # merged_list_file.sh定时任务加入cookies环境变量脚本 if ! [ `grep -c "$FIND_STR" $FIND_FILE` -ne '0' ];then sed -i 's/\/scripts\/logs\/auto_help_export\.log/\/scripts\/logs\/auto_help_export\.log \&\& \. \/scripts\/docker\/export_jd_cookies_script_orz\.sh/g' $FIND_FILE ## 更新定时任务列表 crontab $FIND_FILE fi CRZAY_JOY_COIN_FILE="/scripts/docker/proc_file.sh" # joy coin脚本加入cookies环境变量脚本 if ! [ `grep -c "$FIND_STR" $CRZAY_JOY_COIN_FILE` -ne '0' ];then sed -i 's/node \/scripts\/jd_crazy_joy_coin\.js/\. \/scripts\/docker\/export_jd_cookies_script_orz\.sh \&\& node \/scripts\/jd_crazy_joy_coin\.js/g' $CRZAY_JOY_COIN_FILE sh -x /scripts/docker/proc_file.sh fi 该脚本主要是每分钟执行,但是只修改一次merged_list_file.sh定时任务文件,并且立即更新crontab list,为每个京东任务定时脚本执行前先更新JD_COOKIE环境变量,这样你得脚本执行才能正确获取cookie。第二个是joy coin脚本,这个脚本没有在定时任务列表中,每天只会执行一次,所以要单独修改后并启动。 因为是每分钟执行,所以可以很大程度上避免cookie没有导入的尴尬。 你过你还需要其他环境变量或者磁盘挂载记得自己加。 单容器只有创建容器时配置好的通知环境变量接收通知,没法多个用户分发的。而且人数一多执行单个脚本时间会延长。优点就是可以添加环境变量配置ENABLE_AUTO_HELP=true开启单容器多用户互助。 2021-03-16更新结束。 脚本地址:jd_scripts telegram bot python3.8, python3.9都没问题,其他环境没测试,我使用python3.9开发,openwrt上是3.8没有发现问题。 openwrt上安装pip请点击get-pip。 之前python用的qrcode包生成二维码,但是默认只有svg格式,想生成png,jpg就需要Pillow包,但是这个包在openwrt上安装一直报错,确少zlib库,这个好解决,安装zlib-dev就好了,然后又提示缺少jpeg,这个库openwrt已经用libjpeg-turbo替换了libjpeg库,就算安装了libjpeg-turbo也还是不行,所以换成segno包了。 需要安装包(不知道是不是有遗漏): pip install segno python-telegram-bot peewee redis 脚本已经撸出来了,做个说明吧!自己用也没太多讲究(记得删除注释): [telegram_bot] token = 88888888:AAAAAAAAAAAAAAAA //这是telegram bot token port = 8080 //监听端口, frp请填写web端本地端口(local_port),openwrt别配置80端口,不然都无法启动telegram脚本,因为openwrt web端已经占用了80端口 admins=88888888,8888888 //管理员用户,如果指定了管理员就只能管理员使用京东docker命令,获取自己的userid看这里https://gitee.com/lxk0301/jd_docker/blob/master/backUp/TG_PUSH.md url=https://telegram.bot/ // telegram bot webhook发送域名 redis_cache_prefix=telegram_bot: //redis缓存前缀,可以随便改 commands=jd_script_start:登陆京东并且创建docker容器 //命令,可以自行添加,命令格式 命令:命令说明,命令:命令说明,命令:命令说明 多命令逗号隔开 [jd_scripts] existed_docker_container_name = jd_scripts_orzlee //已经创建好的容器名称,主要用于执行`/scripts/getJDCookies.js`脚本给用户登陆 existed_docker_container_id=1919c3ff9e45ee6d1ca58xxxxxxxxxxxxxx5a8d //已经创建好的容器id,主要用于复制配置文件 docker_container_prefix = jd_scripts_ //新建docker容器名称前缀 tg_bot_token=88888888:AAAAAAAAAAAAAAAA //jd_scirpts 脚本推送通知bot token,可以和上面一样,可以使用其他token,推送用户就是谁请求的二维码,通知就会推送给谁 min_login_days=10 //最少登陆多少天才能重新使用,这个是怕已经成功创建容器后,用户一直用同一个京东账户扫码,然后服务器不停的删除容器创建容器,单位是天,可自行修改,0就是不设置 max_docker_num=50 //最大用户数量,这是判断Sqlite数据库用户数量决定的,不是你本地docker容器数量 auto_delete_docker_by_days=30 //目前没有实现自动删除过期用户容器功能,只是attach模式中过滤超过N天的用户cookie add_user_mode=attach //创建容易方式:attach 附加,create 创建,附加只会追加cookie到existed_docker_container_name配置容器里,create每一个用户都会创建一个新的docker容器 [sqlite] database=telegram_bot_jd_scripts.db //数据库文件名称 环境变量和挂载我给写死了,需要自己修改下吧! 命令由于有"号,所以要转义,在shell中要转义\",代码中就必须转义\和",所以环境变量和挂载磁盘都需要\\\"环境变量=xxx(挂载参数:xxx)\\\"包含起来,因为这个基本不会改变,所以没有放入配置文件,你可以继续加或者删掉部分,像JDCOOKIE和TG_USER_ID这些都是用户的变量,所以还是留下吧: from src.config import * from src import common def createAndStartContainer(cookie, tgUserId, name): ##lua newcontainer.lua -n jd_scripts_test -e \"JD_COOKIE=pt_key=AAJgSIA0ADC-1mV_7uCjZK2kIBxYN4sdb1L9PyAktQewf5Hse7QHaFJVBE3egdRZugQF0FeiWvI\;pt_pin=fangxueyidao\;\",\"RANDOM_DELAY_MAX= ##600\",\"TG_BOT_TOKEN=644204874\:AAETxq7Wr2-rXEijjKYJqn3vXsCijG6xm-w\",\"TG_USER_ID=490884842\",\"CUSTOM_SHELL_FILE=https://raw.githubusercontent.com/jianminLee/jd_scripts/main/docker_shell.sh\" -m \"/opt/jd_scri ##pts/logs:/scripts/logs\" ## 拼接参数 n = env['jd_scripts']['docker_container_prefix'] + name e = '\\\"JD_COOKIE='+cookie.strip()+'\\\",\\\"RANDOM_DELAY_MAX=600\\\",\\\"TG_BOT_TOKEN=' \ +env['jd_scripts']['tg_bot_token'] \ +'\\\",\\\"TG_USER_ID='+str(tgUserId)+'\\\"' m = '\\\"/opt/jd_scripts/logs/'+ str(tgUserId) +':/scripts/logs\\\"' command = ("cd "+ os.path.abspath('lua/') +" && lua "+ os.path.abspath('lua/dockerman.lua') +" -n " + n + ' -e ' + e + ' -m ' + m + ' -d ' + env['jd_scripts']['existed_docker_container_id']).replace(';','\\;') print(n+'\n'+e+'\n'+m+'\ncommand:'+command) result = common.run_command(command) for res in result: if res.startswith('id:'): #返回容器ID return res[3:] return -1 def stopAndDeleteContainer(containerId): command = 'cd '+os.path.abspath('lua/')+' && lua '+os.path.abspath('lua/dockerman.lua')+' -D '+containerId result = common.run_command(command) for res in result: if res == 0: #返回容器ID return 0 return -1 lua管理docker命令参数说明: { "-m, --mount", help = "容器挂载目录" }, { "-d, --duplicate", help = "容器ID 复制容易配置,复制后依然可以使用其他选项覆盖" }, { "-D, --delete", help = "容器ID 删除容器" }, { "-n, --name", help = "容器名称" }, { "-e, --env", help = "容器环境变量" }, 运行的话使用python serve.py。 frp服务配置 eSir的openwrt高大全版本固件中服务-frp内网穿透可以看到frp工具(服务器下面的端口是1234,和frps.ini中的bind_port一致): 添加一个客户端,自定义域名随便起,不用注册,内网使用: 服务器安装可以看之前的文章frp内网穿透,但是我这里使用nginx反向代理安装。 frps.ini配置: [common] bind_port = 1234 vhost_http_port = 8080 token = AAAAAAAAAA type = http custom_domains = orzlee.test //这个域名和客户端自定义域名一致 nginx反向代理配置: server { listen 80; server_name 你的域名; ###rewrite ^(.*) https://$server_name$1 permanent; charset utf-8; location / { proxy_pass http://127.0.0.1:8080; ##端口是frps.ini中的vhost_http_port端口 proxy_set_header Host orzlee.test; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; } ##location = /favicon.ico { access_log off; log_not_found off; } ##location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log off; sendfile off; location ~ /\.ht { deny all; } } server { listen 443 ssl http2; server_name 你的域名; ssl_certificate 证书目录/xxx.cer; ssl_certificate_key 证书私钥xxx.key; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; #屏蔽不安全的加密方式 ssl_prefer_server_ciphers on; index index.html index.htm index.php; charset utf-8; client_max_body_size 5M; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host orzlee.test; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; } ##location = /favicon.ico { access_log off; log_not_found off; } ##location = /robots.txt { access_log off; log_not_found off; } access_log off; error_log off; sendfile off; location ~ /\.ht { deny all; } } 这样frp就通了,然后本地telegram-bot就可以接收webhook通知了。 结语 后续还有很多需要实现的功能,例如自动删除一个月以后的docker容器,因为可能cookie过期了,再继续跑下去也没有什么意义,还占用资源。等之后有时间在弄吧,折腾这个把openwrt弄挂了,还好有备份!
2021-03-03
LXK0301京东签到脚本-京喜工厂解决无法签到异常
前言 LXK0301大佬的京喜工厂自动签到脚本不知怎么一直提示:亲,活动太火爆了,请稍后再试吧!,基本无法使用,任务也不自动做了。 上网查了一下,全是说黑号,真蛋疼。因为脚本无法做任务什么的,但是手动完全没有问题,根本不是黑号,网上一股脑说黑号。 我就不信邪,app能做任务脚本就不行,肯定是脚本有问题。 2021-03-25 第二次更新,已经不需要自己抓包获取签名参数了,脚本会在每次执行时自动获取签名参数。已经联系作者,等作者更新吧!(推荐使用作者脚本,修复了参团问题) 2021-03-25更新,今天更新了下脚本,应该可以获取自己的签名参数使用了,有时间的朋友可以测试一下!仓库地址:jd_scripts-orzlee 2021-03-23更新,自己获取签名的方法可能无效,作者已经跟新脚本,目前使用我提供的签名参数可以正常做任务和领取电力,后续可能还需要研究。更新作者脚本即可! 原因 最根本的原因就是脚本发送请求链接签名有问题,这个好像只针对了部分用户,有的用户没问题,有的就会一直提示:亲,活动太火爆了,请稍后再试吧!。 起初发现问题是在手机上用QuantumultX抓包京喜APP,点击地上的零件,再抓包脚本,然后找出usermaterial/PickUpComponent请求来对比。开始我还以为是cookie问题,我替换cookie重试请求还是太火爆错误,再重发一下抓包京喜APP的请求,依然成功。再替换替换脚本请求的url参数为抓包app的,莫名奇妙的成功了。这个锅必须脚本背了! 脚本中decrypt函数是负责请求链接签名的,但是目前脚本有问题,很多签名key都是没有值的,因为根本没有获取值,只有少部分定义了默认值。来看一下代码(目前是1535行): function decrypt(time, stk, type) { if (stk) { const random = 'pmUmA8IyRcDp'; //这些常量其实每个用户都可能不一样 const token = `tk01wd4571d58a8nT0tkdXczeW94f5x4qjWs44kcPCTXeWKa2xXY+ZxHaOtbRxmyw6vrIF4RDFwwTUfwy1pIqNE0oyWW`; //这些常量其实每个用户都可能不一样 const fingerprint = 8410347712257161; //这些常量其实每个用户都可能不一样 //这个时间转换和现在的不一样,现在是new Date(time).Format("yyyyMMddhhmmssSSS");,转换结果不一样,加密出来也不一样 const timestamp = new Date(time).Format("yyyyMMddhhmmssS"); const appId = 10001; //这个是活动id 是固定的 const str = `${token}${fingerprint}${timestamp}${appId}${random}`; const hash1 = $.CryptoJS.HmacSHA512(str, token).toString($.CryptoJS.enc.Hex); //这里加密算法有可能不一样 let st = ''; stk.split(',').map((item, index) => { //下面的签名参数只有些默认值,很多都是空的,但是链接上又带了有效值,服务器验签估计不合法(但是有的用户却没有问题,搞不懂) st += `${item}:${item === '_time' ? time : item === 'zone' ? 'dream_factory' : item === 'type' ? type || '1' : ''}${index === stk.split(',').length -1 ? '' : '&'}`; }) const hash2 = $.CryptoJS.HmacSHA256(st, hash1).toString($.CryptoJS.enc.Hex); console.log(`st:${st}\n`) // console.log(`hash2:${JSON.stringify(["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)])}\n`) console.log(`h5st:${["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)].join(";")}\n`) return ["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)].join(";") } else { return '20210121201915905;8410347712257161;10001;tk01wa5bd1b5fa8nK2drQ3o3azhyhItRUb1DBNK57SQnGlXj9kmaV/iQlhKdXuz1RME5H/+NboJj8FAS9N+FcoAbf6cB;3c567a551a8e1c905a8d676d69e873c0bc7adbd8277957f90e95ab231e1800f2' } } 研究过程我就不再多说了,京东那边全是混淆的JS,真的很头疼,我弄了一下午才摸清楚他的逻辑。 整个流程大概是这样(官方的js混淆了,乱七八糟的就不贴代码了): 第一次进入活动页面会发送POST请求:https://cactus.jd.com/request_algo?g_ty=ajax,将返回结果储存在本地(这个默认应该没有有效期,但是京喜工厂里面的JS会设置有效期,过期会重新获取)。已经更新脚本自动获取签名参数了。 请求参数: { appId: "10001" expandParams: "" //fingerprint //pc浏览器我试过,就算拿到所有数据跑脚本依然不行,还是太火爆错误。所以保险还是去京喜APP抓包吧! fp: "5525701123405161" platform: "web" timestamp: 1614687205087 version: "1.0" } 接口会返回: { data: { result: { //加密函数 algo: "function test(token,fingerprint,timestamp,appId,algo){const random='jQ1SS0VI2Vuw';const str=`${token}${fingerprint}${timestamp}${appId}${random}`;return algo.SHA512(str)}" //加密token tk: "tk01w91541b51a8nWURUM3hiZk9HHRKep5j4FeOg/jHOQoGSDcsasdSOZ+83iz4uf/YBXHcK6xMIUqqv5/iJv6F0aooT5Nd3" } version: "1.0" message: "" status: 200 } } 这个接口会返回所有签名需要的参数,也就是脚本中decrypt中的参数,其实照着值样子都知道怎么替换了。 当前时间格式转换new Date(time).Format("yyyyMMddhhmmssSSS")这个时间是和链接参数中的'_time匹配'。 字符串拼接${token}${fingerprint}${timestamp}${appId}${random}。 第一次签名,将第三步的字符串用SHA或者MD5加密,这个主要参考第一步中的机密函数: function test(token,fingerprint,timestamp,appId,algo){ const random='jQ1SS0VI2Vuw'; const str=`${token}${fingerprint}${timestamp}${appId}${random}`; return algo.SHA512(str) } 这个函数提供了加密方法和随机字符串,官方直接用它做闭包函数第一次签名。 第一次签名完成后,开始第二次了,这个参数每个接口可能不同,它会按照请求url中的_stk参数来提供签名参数,例如&_stk=_time,pin,placeId,zone,那么就需要将参数拼接成time:xxxx&pin:xxxx&placeId:xxxx&zone:xxx这样子。stk参数的值也会包含在url中,例如: https://m.jingxi.com/dreamfactory/usermaterial/PickUpComponent?zone=dream_factory&placeId=1&pin=91DCBu8VvYt6rEdezHZ_VQ%3D%3D&_time=1614622722731&_stk=_time%2Cpin%2CplaceId%2Czone&_ste=1&h5st=20210302021842732%3B6099600123439161%3B10001%3Btk01wa66691cafa8nSmV1UDN2SWtZAiPI1uR1EAuPwYDaw36v9gQGhJz5Ac4h2cjfkeCQexVweqwa6%2BsjvERwkVU6wxTK%3Ba795we798qwe789789qe8262584d49f9449a1ce0194bb26c72049eef428f5e23e1043a641d&_=1614622722744&sceneval=2&g_login_type=1&callback=jsonpCBKR&g_ty=ls 第二次签名加密的算法是固定的,SHA256。 最后拼接: ["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)].join(";") 抓包 2021-03-04 更新可以免去抓包和修改脚本操作了: 一旦有一个设备的url签名参数更新,其他设备都会失效,如果多设备跑同一个账号要保持一直,否则还是会失败的!!! 我更新了脚本,不需要手动抓包了,QuantumultX可以添加url_sign_params.conf重写引用,其他平台可能需要自己写一下。然后删除京喜APP,重新下载后进入京喜工厂(最好重下APP,不然有可能还是太火爆异常,如果没有提示退出京喜工厂再进一次,多试试!): 折腾好了就只使用京喜APP进入京喜工厂(url签名参数会被京喜工厂里面的JS设置过期时间,过期会重新获取),以免从京东APP进入京喜工厂跳转到京喜APP重新获取覆盖,京东APP里面的京喜工厂获取的url签名参数也不能执行成功!只能使用京喜APP的url签名参数! 日志可以查看url签名参数: 以下为未更新之前的方法: 找到了问题就好解决了,抓包京喜APP一个请求就行了,抓包之前建议先删除APP,因为签名参数会存在本地,基本上弄不到了。删掉APP再进入京喜工厂之前,准备好抓包工具,IOS可以用QuantumultX、Surge等,PC抓包太多了,一搜一大把。 准备好抓包工具之后,进入京喜工厂,等待完全进入工厂,最好再捡下零件。没有报错就可以关掉抓包工具了。 搜索algo,找到签名参数请求: 请求JSON和响应JSON都要看,不然你不知道fingerprint参数,是一串数字,在请求JSON里: 复制返回请求中的参数: 修改脚本 脚本我修改了很多处,但是很简单: 新增一个获取url参数的函数: /** * 新增url参数获取函数 * @param url_string * @param param * @returns {string|string} */ function getUrlQueryParams(url_string, param) { let url = new URL(url_string); let data = url.searchParams.get(param); return data ? data : ''; } 时间函数与官方不一致,会导致签名结果错误(这函数是官方混淆JS里面扒出来的): /* 修改时间戳转换函数,京喜工厂原版修改 */ Date.prototype.Format = function (fmt) { var e, n = this, d = fmt, l = { "M+": n.getMonth() + 1, "d+": n.getDate(), "D+": n.getDate(), "h+": n.getHours(), "H+": n.getHours(), "m+": n.getMinutes(), "s+": n.getSeconds(), "w+": n.getDay(), "q+": Math.floor((n.getMonth() + 3) / 3), "S+": n.getMilliseconds() }; /(y+)/i.test(d) && (d = d.replace(RegExp.$1, "".concat(n.getFullYear()).substr(4 - RegExp.$1.length))); for (var k in l) { if (new RegExp("(".concat(k, ")")).test(d)) { var t, a = "S+" === k ? "000" : "00"; d = d.replace(RegExp.$1, 1 == RegExp.$1.length ? l[k] : ("".concat(a) + l[k]).substr("".concat(l[k]).length)) } } return d; } decrypt函数也要修改,我加了一个url参数,在拼接签名参数需要的值可以在url中拿(实在不想动太多代码,怎么方便怎么来吧): /* 签名函数 签名信息获取地址:https://cactus.jd.com/request_algo?g_ty=ajax 方法: POST 参数:{ appId: "10001" expandParams: "" fp: "5525701123405161" //fingerprint platform: "web" timestamp: 1614687205087 version: "1.0" } 返回结果:{data: { result: { algo: "function test(token,fingerprint,timestamp,appId,algo){const random='jQ1SS0VI2Vuw';const str=`${token}${fingerprint}${timestamp}${appId}${random}`;return algo.SHA512(str)}" //加密函数 tk: "tk01w91541b51a8nWURUM3hiZk9HHRKep5j4FeOg/jHOQoGSDcsasdSOZ+83iz4uf/YBXHcK6xMIUqqv5/iJv6F0aooT5Nd3" //token } version: "1.0" message: "" status: 200 } } 将返回参数替换: const random : data.result.algo字符串中的const random='xxxxxx' const token : data.result.tk const fingerprint : 通过抓包APP获取 const hash1加密方法(例子:algo.SHA512、algo.MD5,主要看签名信息获取地址返回结果data.result.algo) */ function decrypt(time, stk, type, url) { stk = stk || (url ? getUrlQueryParams(url, '_stk') : '') if (stk) { const random = '1gy8nc5oDM+y'; const token = `tk01w9a771c1aa8nd1k2NUo4UmNaahBe0/qh61gMNV9222JdJwlR0wyO9gko9dFTogSpvPIpqxstZJ9tl8JM9ONKNJWk`; const fingerprint = 5525701217505161; const timestamp = new Date(time).Format("yyyyMMddhhmmssSSS"); const appId = 10001; const str = `${token}${fingerprint}${timestamp}${appId}${random}`; const hash1 = $.CryptoJS.HmacSHA512(str, token).toString($.CryptoJS.enc.Hex); let st = ''; stk.split(',').map((item, index) => { // st += `${item}:${item === '_time' ? time : item === 'zone' ? 'dream_factory' : item === 'type' ? type || '1' : ''}${index === stk.split(',').length -1 ? '' : '&'}`; st += `${item}:${getUrlQueryParams(url, item)}${index === stk.split(',').length -1 ? '' : '&'}`; }) const hash2 = $.CryptoJS.HmacSHA256(st, hash1).toString($.CryptoJS.enc.Hex); console.log(`st:${st}\n`) // console.log(`hash2:${JSON.stringify(["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)])}\n`) console.log(`h5st:${["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)].join(";")}\n`) return ["".concat(timestamp.toString()), "".concat(fingerprint.toString()), "".concat(appId.toString()), "".concat(token), "".concat(hash2)].join(";") } else { return '20210121201915905;8410347712257161;10001;tk01wa5bd1b5fa8nK2drQ3o3azhyhItRUb1DBNK57SQnGlXj9kmaV/iQlhKdXuz1RME5H/+NboJj8FAS9N+FcoAbf6cB;3c567a551a8e1c905a8d676d69e873c0bc7adbd8277957f90e95ab231e1800f2' } } 最后一步了,搜索${decrypt(关键字,大概有8处要修改,主要是团长这部分多,主要还是没有解耦: 参团部分(每一个api不一样,只要剥离出&h5st=${decrypt(xxxxx就行了,单独拼接): //可获取开团后的团ID,如果团ID为空并且surplusOpenTuanNum>0,则可继续开团 //如果团ID不为空,则查询QueryTuan() function QueryActiveConfig() { return new Promise((resolve) => { //option中的url拉出来替换如下 let url = `https://m.jingxi.com/dreamfactory/tuan/QueryActiveConfig?activeId=${escape(tuanActiveId)}&_time=${Date.now()}&_=${Date.now()}&sceneval=2&g_login_type=1&_ste=1` url += `&h5st=${decrypt(Date.now(), '', '', url)}` const options = { 'url': url, //改成变量 "headers": { ... taskurl和newtasksysUrl函数部分: function taskurl(functionId, body = '', stk) { let url = `${JD_API_HOST}/dreamfactory/${functionId}?zone=dream_factory&${body}&sceneval=2&g_login_type=1&_time=${Date.now()}&_=${Date.now()}&_ste=1` url += `&h5st=${decrypt(Date.now(), stk, '', url)}` if (stk) { url += `&_stk=${stk}`; } ... function newtasksysUrl(functionId, taskId, stk) { let url = `${JD_API_HOST}/newtasksys/newtasksys_front/${functionId}?source=dreamfactory&bizCode=dream_factory&sceneval=2&g_login_type=1&_time=${Date.now()}&_=${Date.now()}&_ste=1`; if (taskId) { url += `&taskId=${taskId}`; } if (stk) { url += `&_stk=${stk}`; } //传入url进行签名,加入位置不要错了,不然有些签名参数获取不到值 url += `&h5st=${decrypt(Date.now(), stk, '', url)}` ... 大功告成,发到手机上或者node跑一下试试: 结果非常完美。 docker处理 手机端好办,docker麻烦一点,放到远程或者本地都行,具体看说明jd_scripts docker。docker提供了一个环境变量CUSTOM_SHELL_FILE(你也可以用CUSTOM_LIST_FILE挂载本地定时任务列表,只是更新要手动,要自动还是需要脚本的)可以跑远程shell脚本,jd_scripts docker说明中还有示例,照葫芦画瓢即可。我在github上弄一份自用,你可以参考或者fork一份自己用,地址:jd_scripts-orzlee。只需替换decrypt函数部分常量就好了,shell脚本最好看看我写的注释。然后在环境变量中加入shell脚本地址CUSTOM_SHELL_FILE=https://raw.githubusercontent.com/xxx/xxx.sh即可。 如果用我仓库的远程脚本,务必docker配置环境变量RANDOM_DELAY_MAX=600, 600的值可以自己设置非零正整数,意思是所有脚本每天随机延迟0-600秒执行。 结语 经过不懈努力,终于还是折腾好了,这半个月都是手动点击脚本,人家升级都比我快,没办法手动哪里有脚本那么按时呢!混淆JS浪费不少时间,眼睛都能看瞎。
2021年03月03日
7,197 阅读
75 评论
9 点赞