首页
留言
动态
归档
推荐
音乐
工具
Search
1
Emby公益服-上万部电影电视剧免费看
66,771 阅读
2
openwrt-docker部署lxk0301京东自动签到脚本
12,893 阅读
3
QuantumultX-京东签到撸京东豆
11,188 阅读
4
LXK0301京东签到脚本-自动提交互助码
9,634 阅读
5
微信-域名被封监测以及自动更换被封域名
9,172 阅读
随便写写
科学上网
Web开发
瞎折腾
Search
标签搜索
quantumultx
laravel
openwrt
laravel nova
laradock
telegram
DDC/CL
薅羊毛
google adsense
jd_scripts
京东签到
ubuntu
oh-my-zsh
web开发环境
nginx
工具
shadowsocks shadowsocksR
RBAC
权限管理
内网穿透
orzlee
累计撰写
46
篇文章
累计收到
595
条评论
首页
栏目
随便写写
科学上网
Web开发
瞎折腾
页面
留言
动态
归档
推荐
音乐
工具
搜索到
2
篇与
jd_scripts
的结果
openwrt-通过telegram bot自动创建启动jd-scripts docker容器
2021年03月13日
2,723 阅读
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,335 阅读
75 评论
9 点赞