如何自动运行零信任客户端并获取短信验证码登录

已经可以实现,大致包括如下过程:
1、用KeymouseGo录制按键,播放录制的按键输入零信任客户端用户名,密码,点击发送短信。
2、在手机上安装Android 短信转发器 SmsForwarder,定义转发规则,转发指定内容的验证码到一个邮箱,假设转发包含有【零信任】的短信到一个邮箱,标题设置为Smsforwarder
3、编写程序get_mail.py,获取指定邮箱中的邮件,找出标题是Smsforwarder的邮件,分析出正文中的验证码,取出验证码,复制到剪贴板,把收到的验证码写入一个KeymouseGo的键盘录制文件中,取代指定的验证码按键,注意转码为ASCII编码。删除邮箱中的验证码邮件。
4、调用KeymouseGo播放短信按键,完成登录。

具体的代码有空再整理上来。

2025-1-24

上面的第3和第4点,都可以用get_mail.py程序解决。
程序要求的前提条件是:转发的短信的邮件的标题是:Smsforwarder,程序用于过滤邮箱中的这种标题的邮件。以下程序可以用Visual Studio Code打开,修改程序最后的用户名和密码,也就是说:

在这里插入代码片
if __name__ == '__main__':
    # 替换下面的用户名和密码为你的邮箱信息
    my_username = '13312345678@189.cn'
    my_password = 'Zv@1Zu$5r)8Qh#9I'

完整的程序如下:

import re
import imaplib
import email
from email.header import decode_header
from email.utils import parsedate_to_datetime
import pytz
from datetime import datetime  # 导入 datetime 类
import pyperclip #将文本复制到剪贴板

# python -m site 查看python解释器的安装位置
# 家里安装环境老是不会安装到
# 安装后老是找不到,手工拷贝如下的2个目录到c:\Program Files\Python37\Lib\site-packages\
# c:\users\asus\appdata\local\packages\pythonsoftwarefoundation.python.3.12_qbz5n2kfra8p0\localcache\local-packages\python312\site-packages\pyperclip\
# c:\users\asus\appdata\local\packages\pythonsoftwarefoundation.python.3.12_qbz5n2kfra8p0\localcache\local-packages\python312\site-packages\pyperclip-1.9.0.dist-info\

# __________________________________________________________________________________________________________
#
#  本程序的功能:读取邮件,获取验证码,写入模拟按键序列文件。另外也复制到剪贴板,可直接Ctrl+V复制验证码使用
#___________________________________________________________________________________________________________

#region  定义一个函数来解析邮件中的日期,并与当前时间比较
def compare_dates(date_str):
    # 解析邮件中的日期字符串为 datetime 对象
    # 注意:邮件中的日期通常为 GMT 时间
    email_date = email.utils.parsedate_to_datetime(date_str)
    #email_date = email_date.replace(tzinfo=pytz.utc).astimezone(pytz.timezone('Asia/Shanghai'))  #不用转换时区,原始就是 GMT+8
    # 获取当前时间,并转换为相同的时区以便比较
    current_time = datetime.now(pytz.timezone('Asia/Shanghai'))

    # 计算两个时间之间的差异
    delta = current_time - email_date

    # 输出差异,以分钟为单位
    minutes_difference = int(delta.total_seconds() / 60)
    return minutes_difference
#endregion

#region 转换GMT时间格式为'yyyy-mm-dd HH:MM:SS'格式
def format_date(gmt_date):
    formatted_date="0000-00-00 00:00:00"
    # 解析邮件日期字符串为 datetime 对象
    try:
        dt = parsedate_to_datetime(gmt_date)
    except Exception as e:
        print(f"Error parsing date: {e}")
        dt = None
    # 转换为'yyyy-mm-dd HH:MM:SS'格式
    if dt:
        # 格式化为指定的格式 'yyyy-mm-dd HH:MM:SS'
        formatted_date = dt.strftime('%Y-%m-%d %H:%M:%S')
    else:
        print("Could not parse the date.")

    return formatted_date


#region 写入验证码到键盘操作文件
def write_sms_code(sms_code):
    # 定义源文件路径和目标文件路径
    source_file_path = r'd:\bat\keymouse\scripts\sms_code.template'
    target_file_path = r'd:\bat\keymouse\scripts\sms_code.txt'

    # 验证码需要转化为ASCII码
    str_ascii= ["ASCII1","ASCII2","ASCII3","ASCII4","ASCII5"]
    try:
        # 打开源文件
        with open(source_file_path, 'r', encoding='utf-8') as file:
            content = file.read()

        new_content = content
        # 替换内容
        for i in range(5):
            new_content = new_content.replace(str_ascii[i], str(ord(sms_code[i])) ) # 使用ord()函数来获取一个字符的ASCII码值,数字键0-9对应的ASCII码值48-57
            print(f"{str_ascii[i]} ----> {sms_code[i]}" )


        # 写入新文件
        with open(target_file_path, 'w', encoding='utf-8') as file:
            file.write(new_content)

        print("文件处理完成!")

    except FileNotFoundError:
        print("源文件未找到,请检查路径是否正确。")

    except Exception as e:
        print(f"处理文件时发生错误:{e}")
#endregion


#region 获取电子邮件
#——————————————————————————————————————————————————————————————————————————————
#  获取电子邮件
#——————————————————————————————————————————————————————————————————————————————
def get_mail(username, password, imap_server='imap.189.cn', folder='inbox'):
    minutes_diff=999
    latest_code="0"
    is_zero_trust=False

    # 连接到IMAP服务器
    mail = imaplib.IMAP4_SSL(imap_server)
    mail.login(username, password)

    # 选择邮件夹,默认为收件箱
    mail.select(folder)

    # 搜索所有邮件
    _, search_data = mail.search(None, 'ALL')
    mail_ids = search_data[0].split()

    # 获取最新的5封邮件
    mail_ids = mail_ids[-5:]

    # 遍历邮件ID,打印邮件信息
    for num in mail_ids:
        _, data = mail.fetch(num, '(RFC822)')
        raw_email = data[0][1]
        msg = email.message_from_bytes(raw_email)

        # 解码邮件主题
        subject, encoding = decode_header(msg["Subject"])[0]
        if isinstance(subject, bytes):
            # 如果主题是字节类型,则解码为字符串
            subject = subject.decode(encoding)


        # 解析并解码发件人信息
        decoded_from = decode_header(msg.get("From"))
        from_parts = []
        for part in decoded_from:
            if isinstance(part[0], bytes):
                # 解码每一部分为字符串
                from_parts.append(part[0].decode(part[1] or 'utf-8'))
            else:
                from_parts.append(part[0])

        from_ = ''.join(from_parts)

        # 获取邮件收到时间
        date = msg.get('Date')     # 类似这样的格式:Wed, 15 Jan 2025 15:28:52 +0800 (GMT+08:00)
        formatted_date=format_date(date)  #转化为容易阅读的格式 2025-01-15 15:28:52

        # 获取邮件正文
        body = None
        if msg.is_multipart():
            for part in msg.walk():
                content_type = part.get_content_type()
                if content_type == 'text/plain' or content_type == 'text/html':
                    body = part.get_payload(decode=True).decode(part.get_content_charset() or 'utf-8')
                    break
        else:
            body = msg.get_payload(decode=True).decode(msg.get_content_charset() or 'utf-8')

        # 打印邮件接收时间与当前时间相差多少分钟
        minutes_diff = compare_dates(date)


        if ("SMS" in from_  and  minutes_diff<=60 ):
            print(f"Subject: {subject}")
            print(f"From: {from_}")
            print(f"Received Date: {formatted_date}")
            print(f"Time difference from now: {minutes_diff} minutes")
            print(f"Body:\n{body}")
            # 给定的字符串
            s = body

            # 使用正则表达式匹配所有数字序列
            verification_code = re.findall(r'\d+', s[s.find("<br>") + len("<br>"):s.find("随机短信密码")])   #查找<br>xxxxx随机短信密码之间的数字
            #正则表达式解释  \d+ 匹配一个或多个数字字符。 re.findall(r'\d+', ...) 查找给定范围内的所有数字序列。

            is_zero_trust = True
            if ( "【天翼账号】" in s ):
                verification_code = re.findall(r'\d+', s[s.find("【天翼账号】您的验证码为:") + len("【天翼账号】您的验证码为:"):s.find("尊敬的客户")])   #查找<br>xxxxx。尊敬的客户之间的数字
                is_zero_trust = False

            if ( "【云电脑】" in s  or "【云认证】" in s or "【通义】" or s in "【天翼云】" or s in  "【深度求索】"  ) :
                verification_code = re.findall(r'\d+', s[s.find("验证码") + len("验证码"):s.find("有效")])   #验证码:xxxxxx,5分钟内有效之间的数字
                is_zero_trust = False

            if ( "随机短信验证码" in s  ) :
                verification_code = re.findall(r'\d+', s[s.find("随机短信验证码")-5:s.find("随机短信验证码")+6])   #21692随机短信验证码,尊敬的鲁智深,欢迎登录
                if "零信任" in s:
                    is_zero_trust = True
                else:
                    is_zero_trust = False

            print(f"number:{verification_code[0]}")
            latest_code=verification_code[0]
            print("_" * 100)  # 画一条线


    # 注销
    mail.logout()

    if  minutes_diff<=60:
        if latest_code!='0':
            print(f"{latest_code}")
            pyperclip.copy(latest_code)
            print("验证码已经复制到剪裁板。")
    else:
        print("最近60分钟没有收到短信验证码。")
        is_zero_trust = False


    # 写入验证码到键盘文件
    if ( is_zero_trust  ):          #是零信任的验证码才写入模拟按键文件
        write_sms_code(latest_code)
        print(f"写入键盘文件中的验证码{latest_code}")
#endregion 获取电子邮件


#region 删除电子邮件
#——————————————————————————————————————————————————————————————————————————————
#  删除电子邮件
#——————————————————————————————————————————————————————————————————————————————
def delete_mails_by_subject(username, password, subject_to_delete, imap_server='imap.189.cn', folder='inbox'):
    # 连接到IMAP服务器
    mail = imaplib.IMAP4_SSL(imap_server)
    mail.login(username, password)

    try:
        # 选择邮件夹,默认为收件箱
        mail.select(folder)

        # 搜索包含指定主题的邮件
        status, messages = mail.search(None, 'ALL')
        if status != 'OK':
            print("未找到相关邮件")
            return

        # 获取匹配的邮件ID列表
        mail_ids = messages[0].split()

        if not mail_ids:
            print("找不到指定主题的邮件")
            return

        i=0
        # 遍历邮件ID,打印邮件信息
        for num in mail_ids:
            _, data = mail.fetch(num, '(RFC822)') # 返回的结果是一个元组,其中第一个元素通常是状态信息(这里用下划线_忽略,因为我们不关心这个值),第二个元素data是实际的邮件数据。
            raw_email = data[0][1]
            msg = email.message_from_bytes(raw_email)

            # 解码邮件主题
            subject, encoding = decode_header(msg["Subject"])[0]
            if isinstance(subject, bytes):
                # 如果主题是字节类型,则解码为字符串
                subject = subject.decode(encoding)

            # 解析并解码发件人信息
            decoded_from = decode_header(msg.get("From"))
            from_parts = []
            for part in decoded_from:
                if isinstance(part[0], bytes):
                    # 解码每一部分为字符串
                    from_parts.append(part[0].decode(part[1] or 'utf-8'))
                else:
                    from_parts.append(part[0])

            from_ = ''.join(from_parts)

            # 获取邮件收到时间
            date = msg.get('Date')  # 类似这样的格式:Wed, 15 Jan 2025 15:28:52 +0800 (GMT+08:00)
            formatted_date = format_date(date)  # 转化为容易阅读的格式 2025-01-15 15:28:52

            # 打印邮件接收时间与当前时间相差多少分钟
            minutes_diff = compare_dates(date)

            # 测试需要特别小心,避免错误删除邮件,删除10分钟前指定主题的邮件
            if (minutes_diff>10 ) and (subject_to_delete in subject):
                i = i + 1
                print(i)
                print(f"Subject: {subject}")
                # print(f"From: {from_}")
                print(f"Received Date: {formatted_date}")
                # print(f"Received Date: {date}")
                # print("删除此邮件")
                # print("\n")
                # 标记邮件为删除
                mail.store(num, '+FLAGS', '\\Deleted')

            #最多删除10封邮件,怕错误删除太多了
            if (i>10):
                break
        #for循环结束

        if i>0:
            #永久删除被标记的邮件
            mail.expunge()
            print(f"主题为'{subject_to_delete}'的邮件已删除,删除的邮件数量是{i}。")
        else:
            print(f"没有删除任何主题为'{subject_to_delete}'的邮件。")


    finally:
        # 注销并关闭连接
        mail.logout()
#endregion 删除电子邮件

# —————————————————————————————— 主程序开始 ——————————————————————————————————
if __name__ == '__main__':
    # 替换下面的用户名和密码为你的邮箱信息
    my_username = '13312345678@189.cn'
    my_password = 'Zv@1Zu$5r)8Qh#9I'

    # 获取电子邮件
    get_mail(my_username, my_password)

    # 删除电子邮件
    # delete_mails_by_subject(my_username, my_password, 'Smsforwarder')

执行程序是:python get_mail.py
其实在零信任拨号客户端登录时,是被KeymouseGo使用,读取键盘按键文件中新接收到的验证码,在输入验证码的界面中输入验证码。验证码一般是每次都不一样的,是动态变化的,通用的鼠标键盘按键序列记录文件是固定的,只需替换掉里面的验证码就可以了。
如果不是全程自动化按键的话,那么可以拿到这个验证码,粘贴使用,不用看手机,也不用录入,直接粘贴使用,因为这个程序已经把验证码复制到windows的剪贴板中去了。为了好看一些,用C#做个windows桌面程序去调用这个python程序,拿到的验证码可直接Ctrl+V使用。
程序在189邮箱测试使用了一段时间,删除电子邮件是只删除超过10分钟的验证码邮件,删除邮件的代码,如果要修改,请特别注意删除条件的设置,代码中是直接清空要删除的邮件,如不需要可去掉。在测试时不小心删除很多邮件,幸亏已经都存入本地的foxmail邮箱中了。再次说一下,删除邮件的代码请特别留意删除条件,不错误删除了。这里的主程序入口,先注解掉删除邮件的功能。
如有的地方不明白的话,可以直接复制代码到通义千问,或者深度求索中去,请他给出解释。删除邮件前本来是不用遍历去查找特定主题的邮件的,可以用mail.search去处理的,不知道为何不起作用,只好遍历去查找特定主题了。

    # status, messages = mail.search(None, f'SUBJECT "{encoded_subject}"') #不起作用,很奇怪
    status, messages = mail.search(None, 'before "1-Jan-2025"' )    #能够起作用

2025-1-26

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值