openwrt-通过telegram bot自动创建启动jd-scripts docker容器

openwrt-通过telegram bot自动创建启动jd-scripts docker容器

orzlee
2021-03-13 / 8 评论 / 2,500 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2021年05月08日,已超过1078天没有更新,若内容或图片失效,请留言反馈。

telegram-jd.jpg

前言

使用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

整个流程:

  1. 用户在telegram bot发送命令
    telegram-bot-command-tips.png
  2. telegram bot返回一个京东登陆二维码(以下图片中的login命令是测试时候的)
    telegram-bot-login-command.png
  3. 用户扫码二维码,服务器获取用户京东cookie
  4. 服务器拿到cookie创建(或删除重建)一个jd_scripts-docker容器,并且启动
  5. 提示用户启动成功或失败
    telegram-bot-login-success.png
    telegram-bot-login-timeout.png
    telegram-bot-tips.png
    telegram-bot-login-failed1.png
  6. 成功后可以在openwrt web端docker-容器看到新加入的用户docker容器,还可以在openwrt的dockerman插件中管理容器。

思路:

  1. 用户发送命令给telegram bot,服务器接收到后进入配置好的容器,执行/scripts/getJDCookies.js脚本获取脚本生成的京东登陆链接,用链接生成二维码,通过telegram bot返回给用户。二维码有效期三分钟,脚本也会持续三分钟。用户扫码后服务器会捕获到脚本回显,提取京东cookie。

  2. 拿到cooki后判断用户是否已经创建容器,创建了多久,超过N天的删除旧容器,然后再创建一个新的容器启动,没有使用过的用户直接创建一个新的。由于我想兼容dockerman,所以用lua语言折腾了一个简版创建和管理docker命令行脚本。懒得折腾了,服务器直接复制一份已存在的jd_scripts-docker脚本配置新建,环境变量和脚本可以自行配置就行了。启动成功捕获命令行回显容器ID,容器ID和用户信息,京东cookie存Sqlite数据库。

  3. 由于防止用户频繁提交,使用reids存下已经获取二维码的telegram用户ID,必须等待三分钟或者jd_scripts-docker成功后再次获取。

本来是想使用一个容器,然后在容器里面修改JDCOOKIE环境变量,配置多个cookie。但是目前有两个缺点:

  1. 单容器多用户跑脚本时会一个个跑,并不是并发跑,人数一多脚本执行时间会很长(如果限制单容器用户人数也许是个办法,比如说一个容器只允许5个用户,多出来的再建个新容器,以后再说吧!)。
  2. 脚本通知(多账号)只能发给一个环境变量配置好的接收用户。

不过最近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模式方法:

  1. 现在开始准备新建一个容器,挂载cookies.sh文件到jd_scripts_docker容器(export_jd_cookies_script_orz.sh挂载文件名要改的话下面的脚本内容也要跟着修改):

     你的目录/cookies.sh:/scripts/docker/export_jd_cookies_script_orz.sh
  2. 添加一个自定义脚本:
    先挂载本地脚本(名称目录自定,但是挂载后的不要改了,不然又要改脚本内容。如果远程脚本就不用挂载了):

     你的目录/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
  3. 挂载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一致):
openwrt-frp.png
添加一个客户端,自定义域名随便起,不用注册,内网使用:
openwrt-frp-add.png

服务器安装可以看之前的文章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弄挂了,还好有备份!

0
取消
扫码打赏
支付金额随意哦!

评论 (8)

取消
  1. 头像
    悉茗
    Windows 10 · Google Chrome

    作者已经更新 docker 容器之后能通过 telegram bot 修改 cookies 吗,没有看到指令。

    回复
    1. 头像
      orzlee 作者
      Linux · Google Chrome
      @ 悉茗

      命令 “/eikooc_dj_teg”会返回二维码,获取到了cookie要手动加到logs/cookies.list里面,一行一个,以后自己维护cookies.list文件就好了!

      回复
      1. 头像
        悉茗
        Windows 10 · Google Chrome
        @ orzlee

        维护 cookies.list 文件也可以通过 bot 进行嘛,怎么操作呢?
        “/eikooc_dj_teg” 指令是不是通过 docker/bot/jd_bot 这个文件找到的,感觉更新文档里面都没看到……

        回复
        1. 头像
          悉茗
          Windows 10 · Google Chrome
          @ 悉茗

          谢谢大佬,“/eikooc_dj_teg” 指令是不是通过 docker/bot/jd_bot 这个文件找到的,感觉更新文档里面都没看到……

          回复
          1. 头像
            悉茗
            Windows 10 · Google Chrome
            @ 悉茗

            不小心重复回复了,帮我删了吧谢谢!

            回复
            1. 头像
              orzlee 作者
              Linux · Google Chrome
              @ 悉茗

              没关系!

              回复
          2. 头像
            orzlee 作者
            Linux · Google Chrome
            @ 悉茗

            是在代码里面找到的!

            回复
        2. 头像
          orzlee 作者
          Linux · Google Chrome
          @ 悉茗

          不行,只能自己编辑cookie.list文件!我是代码里面找到的命令!

          回复