From e399aeb6332ffef30a423bbca98aba6892f93a93 Mon Sep 17 00:00:00 2001
From: ramen <1205925392@qq.com>
Date: Tue, 22 Oct 2024 11:20:02 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BF=9C=E7=A8=8B=E5=91=BD?=
=?UTF-8?q?=E4=BB=A4/push=5Fqr=EF=BC=8C=E6=B7=BB=E5=8A=A0<=E6=9C=AC?=
=?UTF-8?q?=E5=9C=B0=E6=89=AB=E7=A0=81=E5=88=B7=E6=96=B0cookie>=E5=BC=80?=
=?UTF-8?q?=E5=85=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package.json | 5 +-
plugins/dynamicwechat/__init__.py | 304 +++++++++++++++++++++---------
2 files changed, 219 insertions(+), 90 deletions(-)
diff --git a/package.json b/package.json
index cc8d895..b726740 100644
--- a/package.json
+++ b/package.json
@@ -856,13 +856,14 @@
},
"DynamicWeChat": {
"name": "修改企业微信可信IP",
- "description": "优先使用cookie,当填写两个第三方token时手机微信可以更新cookie。验证码以?结尾发给企业微信应用。如:110301?",
+ "description": "优先使用cookie,可本地扫码刷新Cookie,当填写两个第三方token时可手机远程更新cookie。",
"labels": "消息通知",
- "version": "1.1.5",
+ "version": "1.2.0",
"icon": "Wecom_A.png",
"author": "RamenRa",
"level": 2,
"history": {
+ "v1.2.0": "远程命令/push_qr,立即推送一次二维码到pushplus。添加<本地扫码刷新cookie>",
"v1.1.5": "将chromium运行设置为headless模式",
"v1.1.4": "放弃self.post_message()的消息推送,还原成send_pushplus_message()",
"v1.1.3": "关闭cookie输入框,延长cookie任务成功时不输出日志,使用设定中的CookieCloud设置"
diff --git a/plugins/dynamicwechat/__init__.py b/plugins/dynamicwechat/__init__.py
index 7fb076c..ded1a5c 100644
--- a/plugins/dynamicwechat/__init__.py
+++ b/plugins/dynamicwechat/__init__.py
@@ -2,6 +2,7 @@ import io
import random
import re
import time
+import base64
from datetime import datetime, timedelta
from typing import Optional
from typing import Tuple, List, Dict, Any
@@ -25,11 +26,11 @@ class DynamicWeChat(_PluginBase):
# 插件名称
plugin_name = "修改企业微信可信IP"
# 插件描述
- plugin_desc = "优先使用cookie,当填写两个第三方token时手机微信可以更新cookie。验证码以?结尾发给企业微信应用。如:110301?"
+ plugin_desc = "优先使用cookie,可本地扫码刷新Cookie,当填写两个第三方token时手机微信可以更新cookie。"
# 插件图标
plugin_icon = "Wecom_A.png"
# 插件版本
- plugin_version = "1.1.5"
+ plugin_version = "1.2.0"
# 插件作者
plugin_author = "RamenRa"
# 作者主页
@@ -49,8 +50,10 @@ class DynamicWeChat(_PluginBase):
_ip_changed = False
# 强制更改IP
_forced_update = False
+ # CloudCookie服务器
_cc_server = None
- _push_qr_now = False
+ # 本地扫码开关
+ _local_scan = False
# 匹配ip地址的正则
_ip_pattern = r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b'
@@ -62,14 +65,19 @@ class DynamicWeChat(_PluginBase):
_wechatUrl = 'https://work.weixin.qq.com/wework_admin/loginpage_wx?from=myhome'
# 检测间隔时间,默认10分钟
_refresh_cron = '*/20 * * * *'
- # _urls = []
+ # 输入的企业应用id
_input_id_list = ''
+ # helloimg的token
_helloimg_s_token = ""
+ # pushplus的token
_pushplus_token = ""
+ # 二维码
_qr_code_image = None
text = ""
+ # 手机验证码
_verification_code = ''
- # _app_ids = []
+ # 过期时间
+ _future_timestamp = 0
# -------cookie add------------
# cookie有效检测
@@ -98,6 +106,7 @@ class DynamicWeChat(_PluginBase):
self._forced_update = False
# self._cookie_valid = False
self._use_cookiecloud = True
+ self._local_scan = False
self._input_id_list = ''
self._cookie_header = ""
self._cookie_from_CC = ""
@@ -114,6 +123,7 @@ class DynamicWeChat(_PluginBase):
self._helloimg_s_token = config.get("helloimg_s_token")
self._cookie_from_CC = config.get("cookie_from_CC")
self._forced_update = config.get("forced_update")
+ self._local_scan = config.get("local_scan")
self._use_cookiecloud = config.get("use_cookiecloud")
self._cookie_header = config.get("cookie_header")
self._ip_changed = config.get("ip_changed")
@@ -144,6 +154,12 @@ class DynamicWeChat(_PluginBase):
# 关闭一次性开关
self._onlyonce = False
+ if self._local_scan:
+ self._scheduler.add_job(func=self.local_scanning, trigger='date',
+ run_date=datetime.now(tz=pytz.timezone(settings.TZ)) + timedelta(seconds=3),
+ name="本地扫码登陆") # 添加任务
+ self._local_scan = False
+
# 固定半小时周期请求一次地址,防止cookie失效
try:
self._scheduler.add_job(func=self.refresh_cookie,
@@ -162,6 +178,51 @@ class DynamicWeChat(_PluginBase):
self._forced_update = False
self.__update_config()
+ @eventmanager.register(EventType.PluginAction)
+ def local_scanning(self, event: Event = None):
+ """
+ 本地扫码
+ """
+ if not self._enabled:
+ logger.error("插件未开启")
+ return
+ if event:
+ event_data = event.event_data
+ if not event_data or event_data.get("action") != "dynamicwechat":
+ return
+
+ try:
+ with sync_playwright() as p:
+ browser = p.chromium.launch(headless=True, args=['--lang=zh-CN'])
+ context = browser.new_context()
+ page = context.new_page()
+ page.goto(self._wechatUrl)
+ time.sleep(3) # 页面加载等待时间
+
+ current_time = datetime.now()
+ future_time = current_time + timedelta(seconds=110)
+ self._future_timestamp = int(future_time.timestamp())
+
+ if self.find_qrc(page):
+ logger.info("请<重新进入!>插件面板扫码!,每20秒检查登录状态,最大尝试5次")
+ max_attempts = 5
+ attempt = 0
+ while attempt < max_attempts:
+ attempt += 1
+ # logger.info(f"第 {attempt} 次检查登录状态...")
+ time.sleep(20) # 每20秒检查一次
+ if self.check_login_status(page, task='local_scanning'):
+ logger.info("登录成功,更新cookie")
+ self._update_cookie(page, context) # 刷新cookie
+ break
+ else:
+ logger.info("未检测到登录,任务结束")
+ else:
+ logger.info("未找到二维码,任务结束")
+ browser.close()
+ except Exception as e:
+ logger.error(f"本地扫码任务: 本地扫码失败: {e}")
+
@eventmanager.register(EventType.PluginAction)
def check(self, event: Event = None):
"""
@@ -175,10 +236,10 @@ class DynamicWeChat(_PluginBase):
event_data = event.event_data
if not event_data or event_data.get("action") != "dynamicwechat":
return
- logger.info("收到命令,开始检测公网IP ...")
- self.post_message(channel=event.event_data.get("channel"),
- title="开始检测公网IP ...",
- userid=event.event_data.get("user"))
+ # logger.info("收到命令,开始检测公网IP ...")
+ # self.post_message(channel=event.event_data.get("channel"),
+ # title="开始检测公网IP ...",
+ # userid=event.event_data.get("user"))
logger.info("开始检测公网IP")
if self.CheckIP():
@@ -278,45 +339,6 @@ class DynamicWeChat(_PluginBase):
}
response = requests.post(pushplus_url, json=pushplus_data)
- def remote_push_qr(self):
- try:
- with sync_playwright() as p:
- # 启动 Chromium 浏览器并设置语言为中文
- browser = p.chromium.launch(headless=True, args=['--lang=zh-CN'])
- context = browser.new_context()
- # ----------cookie addd-----------------
- # cookie = self.get_cookie()
- # if cookie:
- # context.add_cookies(cookie)
- # ----------cookie END-----------------
- page = context.new_page()
- page.goto(self._wechatUrl)
- time.sleep(3)
- if self.find_qrc(page):
- if self._pushplus_token and self._helloimg_s_token:
- img_src, refuse_time = self.upload_image(self._qr_code_image)
- self.send_pushplus_message(refuse_time, f"企业微信登录二维码
")
- # if img_src:
- # self.post_message(
- # mtype=NotificationType.Plugin,
- # title="企业微信登录二维码",
- # text=refuse_time,
- # image=img_src
- # )
- logger.info("二维码已经发送,等待用户 90 秒内扫码登录")
- logger.info("如收到短信验证码请以?结束,发送到<企业微信应用> 如: 110301?")
- time.sleep(90)
- login_status = self.check_login_status(page, '')
- if login_status:
- self._update_cookie(page, context) # 刷新cookie
- self.click_app_management_buttons(page)
- else:
- logger.warning("远程推送任务 未配置pushplus_token 或 helloimg_s_token")
- else:
- logger.warning("远程推送任务 未找到二维码")
- browser.close()
- except Exception as e:
- logger.error(f"远程推送任务 推送二维码失败: {e}")
def ChangeIP(self):
logger.info("开始请求企业微信管理更改可信IP")
@@ -345,7 +367,7 @@ class DynamicWeChat(_PluginBase):
# image=img_src
# )
logger.info("二维码已经发送,等待用户 90 秒内扫码登录")
- logger.info("如收到短信验证码请以?结束,发送到<企业微信应用> 如: 110301?")
+ # logger.info("如收到短信验证码请以?结束,发送到<企业微信应用> 如: 110301?")
time.sleep(90) # 等待用户扫码
login_status = self.check_login_status(page, "")
if login_status:
@@ -483,9 +505,10 @@ class DynamicWeChat(_PluginBase):
# 在这里使用更安全的方式来检查元素是否存在
captcha_panel = page.wait_for_selector('.receive_captcha_panel', timeout=5000) # 检查验证码面板
if captcha_panel: # 出现了短信验证界面
+ logger.info("等待30秒,请将短信验证码请以'?'结束,发送到<企业微信应用> 如: 110301?")
time.sleep(30) # 多等30秒
if self._verification_code:
- logger.info("需要短信验证 收到的短信验证码:" + self._verification_code)
+ logger.info("输入验证码:" + self._verification_code)
for digit in self._verification_code:
page.keyboard.press(digit)
time.sleep(0.3) # 每个数字之间添加少量间隔以确保输入顺利
@@ -501,8 +524,8 @@ class DynamicWeChat(_PluginBase):
logger.error("未收到短信验证码")
return False
except Exception as e:
- logger.debug(str(e))
- # try: # 没有登录成功,也没有短信验证码。 查找二维码是否还存在
+ # logger.debug(str(e)) # 基于bug运行,请不要将错误输出到日志
+ # try: # 没有登录成功,也没有短信验证码
if self.find_qrc(page) and not task == 'refresh_cookie': # 延长任务找到的二维码不会被发送,所以不算用户没有扫码
logger.error(f"用户没有扫描二维码")
return False
@@ -536,7 +559,6 @@ class DynamicWeChat(_PluginBase):
input_area = page.locator('textarea.js_ipConfig_textarea')
confirm = page.locator('.js_ipConfig_confirmBtn')
input_area.fill(self._current_ip_address) # 填充 IP 地址
- logger.info(f"应用ID: {app_id} 已输入公网IP:" + self._current_ip_address)
confirm.click() # 点击确认按钮
time.sleep(3) # 等待处理
self._ip_changed = True
@@ -544,7 +566,9 @@ class DynamicWeChat(_PluginBase):
logger.error(f"未能找打开{app_url}或点击 '{name}' 按钮异常: {e}")
self._ip_changed = False
if "disabled" in str(e):
- logger.info("该应用已被禁用,可能是没有设置接收api")
+ logger.info(f"应用{app_id} 已被禁用,可能是没有设置接收api")
+ if self._ip_changed:
+ logger.info(f"应用: {app_id} 输入IP:" + self._current_ip_address)
return
else:
logger.error("未找到应用id,修改IP失败")
@@ -626,11 +650,11 @@ class DynamicWeChat(_PluginBase):
"current_ip_address": self._current_ip_address,
"ip_changed": self._ip_changed,
"forced_update": self._forced_update,
+ "local_scan": self._local_scan,
"helloimg_s_token": self._helloimg_s_token,
"pushplus_token": self._pushplus_token,
"input_id_list": self._input_id_list,
# "standalone_chrome_address": self._diy_server,
-
"cookie_from_CC": self._cookie_from_CC,
"cookie_header": self._cookie_header,
"use_cookiecloud": self._use_cookiecloud,
@@ -693,7 +717,7 @@ class DynamicWeChat(_PluginBase):
'component': 'VSwitch',
'props': {
'model': 'forced_update',
- 'label': '强制更新',
+ 'label': '强制更新IP',
}
}
]
@@ -719,6 +743,22 @@ class DynamicWeChat(_PluginBase):
}
}
]
+ },
+ {
+ 'component': 'VCol',
+ 'props': {
+ 'cols': 12,
+ 'md': 4
+ },
+ 'content': [
+ {
+ 'component': 'VSwitch',
+ 'props': {
+ 'model': 'local_scan',
+ 'label': '本地扫码刷新Cookie',
+ }
+ }
+ ]
}
]
},
@@ -744,28 +784,6 @@ class DynamicWeChat(_PluginBase):
}
]
},
- # {
- # 'component': 'VRow',
- # 'content': [
- # {
- # 'component': 'VCol',
- # 'props': {
- # 'cols': 12
- # },
- # 'content': [
- # {
- # 'component': 'VTextarea',
- # 'props': {
- # 'model': 'cookie_header',
- # 'label': 'COOKIE',
- # 'rows': 1,
- # 'placeholder': '手动填写cookie'
- # }
- # }
- # ]
- # }
- # ]
- # },
{
'component': 'VRow',
'content': [
@@ -878,35 +896,146 @@ class DynamicWeChat(_PluginBase):
"onlyonce": False,
"forceUpdate": False,
"use_cookiecloud": True,
- # "wechatUrl": "",
+ "use_local_qr": False, # 默认关闭本地扫码
"cookie_header": "",
"pushplus_token": "",
"helloimg_token": "",
"input_id_list": "",
}
+
def get_page(self) -> List[dict]:
- pass
+ # 获取当前时间戳
+ current_time = datetime.now().timestamp()
+
+ # 判断二维码是否过期
+ if current_time > self._future_timestamp:
+ vaild_text = "二维码已过期"
+ color = "#ff0000"
+ else:
+ # 二维码有效,格式化过期时间为 年-月-日 时:分:秒
+ expiration_time = datetime.fromtimestamp(self._future_timestamp).strftime('%Y-%m-%d %H:%M:%S')
+ vaild_text = f"二维码有效,过期时间: {expiration_time}"
+ color = "#32CD32"
+
+ # 如果self._qr_code_image为None,返回提示信息
+ if self._qr_code_image is None:
+ img_component = {
+ "component": "div",
+ "text": "本地扫码刷新cookie任务未运行",
+ "props": {
+ "style": {
+ "fontSize": "22px",
+ "color": "#ff0000",
+ "textAlign": "center",
+ "margin": "20px"
+ }
+ }
+ }
+ else:
+ # 获取二维码图片数据
+ qr_image_data = self._qr_code_image.getvalue()
+ # 将图片数据转为 base64 编码
+ base64_image = base64.b64encode(qr_image_data).decode('utf-8')
+ img_src = f"data:image/png;base64,{base64_image}"
+
+ # 生成图片组件
+ img_component = {
+ "component": "img",
+ "props": {
+ "src": img_src,
+ "style": {
+ "width": "auto",
+ "height": "auto",
+ "maxWidth": "100%",
+ "maxHeight": "100%",
+ "display": "block",
+ "margin": "0 auto"
+ }
+ }
+ }
+
+ # 页面内容,显示二维码状态信息和二维码图片或提示信息
+ base_content = [
+ {
+ "component": "div",
+ "props": {
+ "style": {
+ "textAlign": "center"
+ }
+ },
+ "content": [
+ {
+ "component": "div",
+ "text": vaild_text,
+ "props": {
+ "style": {
+ "fontSize": "22px",
+ "fontWeight": "bold",
+ "color": "#ffffff",
+ "backgroundColor": color,
+ "padding": "8px",
+ "borderRadius": "5px",
+ "display": "inline-block",
+ "textAlign": "center",
+ "marginBottom": "40px"
+ }
+ }
+ }
+ ]
+ },
+ img_component # 添加二维码图片或提示信息
+ ]
+
+ return base_content
@eventmanager.register(EventType.PluginAction)
- def push_qr(self, event: Event = None):
+ def push_qr_code(self, event: Event = None):
"""
- 发送二维码
+ 立即发送二维码
"""
+ if not self._enabled:
+ return
if event:
event_data = event.event_data
if not event_data or event_data.get("action") != "push_qrcode":
return
- logger.info("远程命令开始推送二维码")
- self.remote_push_qr()
+ try:
+ with sync_playwright() as p:
+ # 启动 Chromium 浏览器并设置语言为中文
+ browser = p.chromium.launch(headless=True, args=['--lang=zh-CN'])
+ context = browser.new_context()
+ page = context.new_page()
+ page.goto(self._wechatUrl)
+ time.sleep(3)
+ if self.find_qrc(page):
+ if self._pushplus_token and self._helloimg_s_token:
+ img_src, refuse_time = self.upload_image(self._qr_code_image)
+ self.send_pushplus_message(refuse_time, f"企业微信登录二维码
")
+ logger.info("远程推送任务: 二维码已经发送,等待用户 90 秒内扫码登录")
+ # logger.info("远程推送任务: 如收到短信验证码请以?结束,发送到<企业微信应用> 如: 110301?")
+ time.sleep(90)
+ login_status = self.check_login_status(page, 'push_qr_code')
+ if login_status:
+ if self._use_cookiecloud and self._cc_server:
+ self._update_cookie(page, context) # 刷新cookie
+ else:
+ logger.info("远程推送任务: 没有可用的CookieCloud服务器,只修改可信IP")
+ self.click_app_management_buttons(page)
+ else:
+ logger.warning("远程推送任务: 未配置pushplus_token和helloimg_s_token")
+ else:
+ logger.warning("远程推送任务: 未找到二维码")
+ except Exception as e:
+ logger.error(f"远程推送任务: 推送二维码失败: {e}")
@staticmethod
def get_command() -> List[Dict[str, Any]]:
return [
{
- "cmd": "/push_qr_code",
+ "cmd": "/push_qr",
"event": EventType.PluginAction,
- "desc": "立即推送登录二维码到微信",
+ "desc": "立即推送登录二维码到pushplus",
"category": "",
"data": {
"action": "push_qrcode"
@@ -963,5 +1092,4 @@ class DynamicWeChat(_PluginBase):
self._scheduler.shutdown()
self._scheduler = None
except Exception as e:
- logger.error(str(e))
-
+ logger.error(str(e))
\ No newline at end of file