├── utils └── __init__.py ├── vqq ├── __init__.py └── vqq.py ├── wps └── __init__.py ├── csdn ├── __init__.py └── csdn.py ├── docs ├── img │ ├── qq.gif │ ├── secret.png │ ├── wechat.gif │ ├── scf_timer.png │ ├── submit_url.png │ ├── synology1.jpg │ ├── synology10.jpg │ ├── synology11.jpg │ ├── synology2.jpg │ ├── synology3.jpg │ ├── synology4.jpg │ ├── synology5.jpg │ ├── synology6.jpg │ ├── synology7.jpg │ ├── synology8.jpg │ ├── synology9.jpg │ ├── iqiyi_cookie.png │ └── wechat_group.jpg ├── local.md ├── tencent-scf.md ├── github-actions.md ├── synology.md ├── docker.md └── index.md ├── kgqq └── __init__.py ├── mgtv ├── __init__.py └── mgtv.py ├── motto ├── __init__.py └── motto.py ├── v2ex ├── __init__.py └── v2ex.py ├── wzyd ├── __init__.py └── wzyd.py ├── acfun ├── __init__.py └── acfun.py ├── fmapp ├── __init__.py └── fmapp.py ├── iqiyi └── __init__.py ├── meizu ├── __init__.py └── meizu.py ├── pojie ├── __init__.py └── pojie.py ├── pyasn1 ├── codec │ ├── __init__.py │ ├── ber │ │ ├── __init__.py │ │ └── eoo.py │ ├── cer │ │ ├── __init__.py │ │ └── decoder.py │ ├── der │ │ ├── __init__.py │ │ ├── decoder.py │ │ └── encoder.py │ └── native │ │ └── __init__.py ├── compat │ ├── __init__.py │ ├── calling.py │ ├── dateandtime.py │ ├── string.py │ ├── binary.py │ ├── octets.py │ └── integer.py ├── type │ ├── __init__.py │ ├── error.py │ ├── opentype.py │ ├── tagmap.py │ ├── namedval.py │ └── useful.py ├── __init__.py ├── error.py └── debug.py ├── smzdm ├── __init__.py └── smzdm.py ├── tieba ├── __init__.py └── tieba.py ├── weather ├── __init__.py └── weather.py ├── weibo ├── __init__.py └── weibo.py ├── duokan └── __init__.py ├── mimotion └── __init__.py ├── requirements.txt ├── womail ├── __init__.py └── womail.py ├── youdao ├── __init__.py └── youdao.py ├── zhiyoo ├── __init__.py └── zhiyoo.py ├── bilibili └── __init__.py ├── cloud189 └── __init__.py ├── liantong └── __init__.py ├── music163 └── __init__.py ├── www2nzz ├── __init__.py └── www2nzz.py ├── picacomic ├── __init__.py └── picacomic.py ├── oneplusbbs ├── __init__.py └── oneplusbbs.py ├── docker ├── example │ ├── my_crontab_list.sh │ ├── custom-append-docker-compose.yml │ └── custom-ovrwrite-docker-compose.yml ├── docker-compose.yml ├── Makefile ├── default_list.sh ├── Dockerfile ├── default_task.sh └── start.sh ├── baidu_url_submit ├── __init__.py └── baidu_url_submit.py ├── .github ├── workflows │ ├── docs.yml │ ├── repo-sync.yml │ ├── main.yml │ └── deploy_tencent_scf.yml └── ISSUE_TEMPLATE │ └── CHECKINERROR.md ├── serverless.yml ├── mkdocs.yml ├── LICENSE ├── docker_start.sh ├── rsa ├── __init__.py ├── _compat.py ├── core.py ├── asn1.py ├── transform.py ├── parallel.py ├── randnum.py ├── util.py ├── pkcs1_v2.py ├── pem.py ├── common.py ├── bigfile.py ├── prime.py └── varblock.py ├── index.py ├── .gitignore └── config.py /utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /vqq/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from vqq.vqq import VQQCheckIn 3 | -------------------------------------------------------------------------------- /wps/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from wps.wps import WPSCheckIn 3 | -------------------------------------------------------------------------------- /csdn/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from csdn.csdn import CSDNCheckIn 3 | -------------------------------------------------------------------------------- /docs/img/qq.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/qq.gif -------------------------------------------------------------------------------- /kgqq/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from kgqq.kgqq import KGQQCheckIn 3 | -------------------------------------------------------------------------------- /mgtv/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from mgtv.mgtv import MgtvCheckIn 3 | -------------------------------------------------------------------------------- /motto/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from motto.motto import Motto 3 | -------------------------------------------------------------------------------- /v2ex/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from v2ex.v2ex import V2exCheckIn 3 | -------------------------------------------------------------------------------- /wzyd/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from wzyd.wzyd import WZYDCheckIn 3 | -------------------------------------------------------------------------------- /acfun/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from acfun.acfun import AcFunCheckIn 3 | -------------------------------------------------------------------------------- /fmapp/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from fmapp.fmapp import FMAPPCheckIn 3 | -------------------------------------------------------------------------------- /iqiyi/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from iqiyi.iqiyi import IQIYICheckIn 3 | -------------------------------------------------------------------------------- /meizu/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from meizu.meizu import MeizuCheckIn 3 | -------------------------------------------------------------------------------- /pojie/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pojie.pojie import PojieCheckIn 3 | -------------------------------------------------------------------------------- /pyasn1/codec/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /pyasn1/compat/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /pyasn1/type/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /smzdm/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from smzdm.smzdm import SmzdmCheckIn 3 | -------------------------------------------------------------------------------- /tieba/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from tieba.tieba import TiebaCheckIn 3 | -------------------------------------------------------------------------------- /weather/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from weather.weather import Weather 3 | -------------------------------------------------------------------------------- /weibo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from weibo.weibo import WeiBoCheckIn 3 | -------------------------------------------------------------------------------- /docs/img/secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/secret.png -------------------------------------------------------------------------------- /docs/img/wechat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/wechat.gif -------------------------------------------------------------------------------- /duokan/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from duokan.duokan import DuoKanCheckIn 3 | -------------------------------------------------------------------------------- /mimotion/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from mimotion.mimotion import MiMotion 3 | -------------------------------------------------------------------------------- /pyasn1/codec/ber/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /pyasn1/codec/cer/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /pyasn1/codec/der/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests~=2.25.1 2 | cryptography~=3.2.1 3 | rsa~=4.0 4 | urllib3~=1.26.2 -------------------------------------------------------------------------------- /womail/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from womail.womail import WoMailCheckIn 3 | -------------------------------------------------------------------------------- /youdao/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from youdao.youdao import YouDaoCheckIn 3 | -------------------------------------------------------------------------------- /zhiyoo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from zhiyoo.zhiyoo import ZhiyooCheckIn 3 | -------------------------------------------------------------------------------- /bilibili/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from bilibili.bilibili import BiliBiliCheckIn 3 | -------------------------------------------------------------------------------- /cloud189/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from cloud189.cloud189 import Cloud189CheckIn 3 | -------------------------------------------------------------------------------- /docs/img/scf_timer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/scf_timer.png -------------------------------------------------------------------------------- /docs/img/submit_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/submit_url.png -------------------------------------------------------------------------------- /docs/img/synology1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology1.jpg -------------------------------------------------------------------------------- /docs/img/synology10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology10.jpg -------------------------------------------------------------------------------- /docs/img/synology11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology11.jpg -------------------------------------------------------------------------------- /docs/img/synology2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology2.jpg -------------------------------------------------------------------------------- /docs/img/synology3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology3.jpg -------------------------------------------------------------------------------- /docs/img/synology4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology4.jpg -------------------------------------------------------------------------------- /docs/img/synology5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology5.jpg -------------------------------------------------------------------------------- /docs/img/synology6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology6.jpg -------------------------------------------------------------------------------- /docs/img/synology7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology7.jpg -------------------------------------------------------------------------------- /docs/img/synology8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology8.jpg -------------------------------------------------------------------------------- /docs/img/synology9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/synology9.jpg -------------------------------------------------------------------------------- /liantong/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from liantong.liantong import LianTongCheckIn 3 | -------------------------------------------------------------------------------- /music163/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from music163.music163 import Music163CheckIn 3 | -------------------------------------------------------------------------------- /pyasn1/codec/native/__init__.py: -------------------------------------------------------------------------------- 1 | # This file is necessary to make this directory a package. 2 | -------------------------------------------------------------------------------- /www2nzz/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from www2nzz.www2nzz import WWW2nzzCheckIn 3 | -------------------------------------------------------------------------------- /docs/img/iqiyi_cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/iqiyi_cookie.png -------------------------------------------------------------------------------- /docs/img/wechat_group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaDai9527/womail/HEAD/docs/img/wechat_group.jpg -------------------------------------------------------------------------------- /picacomic/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from picacomic.picacomic import PicacomicCheckIn 3 | -------------------------------------------------------------------------------- /oneplusbbs/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from oneplusbbs.oneplusbbs import OnePlusBBSCheckIn 3 | -------------------------------------------------------------------------------- /docker/example/my_crontab_list.sh: -------------------------------------------------------------------------------- 1 | 0 18 * * * python /dailycheckin/index.py >> /dailycheckin/logs/dailycheckin.log 2>&1 -------------------------------------------------------------------------------- /baidu_url_submit/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from baidu_url_submit.baidu_url_submit import BaiduUrlSubmit 3 | -------------------------------------------------------------------------------- /pyasn1/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # https://www.python.org/dev/peps/pep-0396/ 4 | __version__ = '0.4.8' 5 | 6 | if sys.version_info[:2] < (2, 4): 7 | raise RuntimeError('PyASN1 requires Python 2.4 or later') 8 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dailycheckin: 4 | image: sitoi/dailycheckin:latest 5 | container_name: dailycheckin 6 | restart: always 7 | tty: true 8 | volumes: 9 | - ./config:/dailycheckin/config 10 | - ./logs:/dailycheckin/logs -------------------------------------------------------------------------------- /pyasn1/type/error.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1.error import PyAsn1Error 8 | 9 | 10 | class ValueConstraintError(PyAsn1Error): 11 | pass 12 | -------------------------------------------------------------------------------- /docker/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build up stop pull logs down exec 2 | 3 | build: 4 | docker-compose build --no-cache 5 | up: 6 | docker-compose up -d 7 | stop: 8 | docker-compose stop 9 | down: 10 | docker-compose down 11 | pull: 12 | docker-compose pull 13 | logs: 14 | docker-compose logs -f 15 | exec: 16 | docker exec -it dailycheckin sh -------------------------------------------------------------------------------- /docker/default_list.sh: -------------------------------------------------------------------------------- 1 | #必须要的默认定时任务请勿删除 2 | 0 */12 * * * sh /dailycheckin/docker/default_task.sh >> /dailycheckin/logs/default_task.log 2>&1 3 | # 每天的 23:50 分清理一次日志 4 | 50 23 */2 * * rm -rf /dailycheckin/logs/*.log 5 | 6 | 7 | ##############每日签到一次任务############## 8 | # 每日签到(8:45 执行一次) 9 | 45 8 * * * python /dailycheckin/index.py >> /dailycheckin/logs/dailycheckin.log 2>&1 10 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: 发布文档 2 | on: 3 | workflow_dispatch: 4 | jobs: 5 | deploy: 6 | name: Deploy docs 7 | runs-on: ubuntu-latest 8 | if: github.event.repository.owner.id == github.event.sender.id 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-python@v2 12 | with: 13 | python-version: 3.x 14 | - run: pip install mkdocs-material pymdown-extensions 15 | - run: mkdocs gh-deploy --force -------------------------------------------------------------------------------- /docker/example/custom-append-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dailycheckin: 4 | image: sitoi/dailycheckin:latest 5 | container_name: dailycheckin 6 | restart: always 7 | tty: true 8 | volumes: 9 | - ./my_crontab_list.sh:/dailycheckin/docker/my_crontab_list.sh 10 | - ./config:/dailycheckin/config 11 | - ./logs:/dailycheckin/logs 12 | environment: 13 | - CUSTOM_LIST_FILE=my_crontab_list.sh 14 | - CUSTOM_LIST_MERGE_TYPE=append -------------------------------------------------------------------------------- /pyasn1/compat/calling.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from sys import version_info 8 | 9 | __all__ = ['callable'] 10 | 11 | 12 | if (2, 7) < version_info[:2] < (3, 2): 13 | import collections 14 | 15 | def callable(x): 16 | return isinstance(x, collections.Callable) 17 | 18 | else: 19 | 20 | callable = callable 21 | -------------------------------------------------------------------------------- /docker/example/custom-ovrwrite-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | dailycheckin: 4 | image: sitoi/dailycheckin:latest 5 | container_name: dailycheckin 6 | restart: always 7 | tty: true 8 | volumes: 9 | - ./my_crontab_list.sh:/dailycheckin/docker/my_crontab_list.sh 10 | - ./config:/dailycheckin/config 11 | - ./logs:/dailycheckin/logs 12 | environment: 13 | - CUSTOM_LIST_FILE=my_crontab_list.sh 14 | - CUSTOM_LIST_MERGE_TYPE=overwrite -------------------------------------------------------------------------------- /pyasn1/compat/dateandtime.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | import time 8 | from datetime import datetime 9 | from sys import version_info 10 | 11 | __all__ = ['strptime'] 12 | 13 | 14 | if version_info[:2] <= (2, 4): 15 | 16 | def strptime(text, dateFormat): 17 | return datetime(*(time.strptime(text, dateFormat)[0:6])) 18 | 19 | else: 20 | 21 | def strptime(text, dateFormat): 22 | return datetime.strptime(text, dateFormat) 23 | -------------------------------------------------------------------------------- /pyasn1/compat/string.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from sys import version_info 8 | 9 | if version_info[:2] <= (2, 5): 10 | 11 | def partition(string, sep): 12 | try: 13 | a, c = string.split(sep, 1) 14 | 15 | except ValueError: 16 | a, b, c = string, '', '' 17 | 18 | else: 19 | b = sep 20 | 21 | return a, b, c 22 | 23 | else: 24 | 25 | def partition(string, sep): 26 | return string.partition(sep) 27 | -------------------------------------------------------------------------------- /motto/motto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import requests 3 | 4 | 5 | class Motto: 6 | @staticmethod 7 | def main(): 8 | """ 9 | 从词霸中获取每日一句,带英文。 10 | :return: 11 | """ 12 | resp = requests.get(url="http://open.iciba.com/dsapi") 13 | if resp.status_code == 200: 14 | content_json = resp.json() 15 | content = content_json.get("content") 16 | note = content_json.get("note") 17 | msg = [f"{content}\n{note}\n"] 18 | else: 19 | msg = [] 20 | return msg 21 | 22 | 23 | if __name__ == "__main__": 24 | Motto().main() 25 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | #组件信息 2 | component: scf # (必选) 组件名称,在该实例中为 scf 3 | name: dailycheckin # (必选) 组件实例名称。 4 | 5 | #组件参数配置 6 | inputs: 7 | name: ${name} # 云函数名称,默认为 ${name}-${stage}-${app} 8 | enableRoleAuth: true # 默认会尝试创建 SCF_QcsRole 角色,如果不需要配置成 false 即可 9 | src: ./ 10 | handler: index.main_handler # 入口 11 | runtime: Python3.6 # 运行环境 12 | region: ap-hongkong # 函数所在区域 13 | description: 每日签到集合 - ${app} 14 | memorySize: 128 # 内存大小,单位 MB 15 | timeout: 900 # 超时时间,单位秒 16 | events: # 触发器 17 | - timer: # 日常签到签到 18 | parameters: 19 | name: dailycheckin 20 | cronExpression: "0 45 8 * * * *" 21 | enable: true 22 | argument: None 23 | -------------------------------------------------------------------------------- /docs/local.md: -------------------------------------------------------------------------------- 1 | # 本地使用教程 2 | 3 | ## 一、下载(Clone)本项目到本地 4 | 5 | > 下载的需要解析压缩包 6 | 7 | 下载地址: [https://github.com/Sitoi/DailyCheckIn/archive/main.zip](https://github.com/Sitoi/DailyCheckIn/archive/main.zip) 8 | 9 | Clone 地址: [https://github.com/Sitoi/dailycheckin.git](https://github.com/Sitoi/dailycheckin.git) 10 | 11 | ## 二、拷贝 `config/config.template.json` 到 `config/config.json` 并修改 12 | 13 | 参考[配置说明文档](https://sitoi.github.io/dailycheckin/settings/) ,并修改 `config/config.json` 14 | 15 | ## 三、安装 Pypi 依赖包 16 | 17 | ```bash 18 | pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 19 | ``` 20 | 21 | ## 四、单次运行 22 | 23 | > 运行【日常签到类】(除喜马拉雅极速版) 24 | 25 | ```bash 26 | python3 index.py 27 | ``` 28 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Daily Check In 2 | site_url: https://github.com/Sitoi/dailycheckin 3 | repo_url: https://github.com/Sitoi/dailycheckin 4 | site_description: 可基于【腾讯云函数】/【GitHub Actions】/【Docker】的每日签到脚本(支持多账号使用) 5 | repo_name: Sitoi/dailycheckin 6 | site_author: Sitoi 7 | theme: 8 | name: material 9 | icon: 10 | repo: fontawesome/brands/github 11 | markdown_extensions: 12 | - pymdownx.highlight 13 | - pymdownx.inlinehilite 14 | - pymdownx.superfences 15 | nav: 16 | - 主页: index.md 17 | - 配置: settings.md 18 | - 教程: 19 | - 本地使用教程: local.md 20 | - Docker 使用教程: docker.md 21 | - 群辉 Docker 使用教程: synology.md 22 | - 腾讯云函数使用教程: tencent-scf.md 23 | - GitHub Actions 使用教程: github-actions.md 24 | -------------------------------------------------------------------------------- /pyasn1/codec/ber/eoo.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1.type import base 8 | from pyasn1.type import tag 9 | 10 | __all__ = ['endOfOctets'] 11 | 12 | 13 | class EndOfOctets(base.SimpleAsn1Type): 14 | defaultValue = 0 15 | tagSet = tag.initTagSet( 16 | tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x00) 17 | ) 18 | 19 | _instance = None 20 | 21 | def __new__(cls, *args, **kwargs): 22 | if cls._instance is None: 23 | cls._instance = object.__new__(cls, *args, **kwargs) 24 | 25 | return cls._instance 26 | 27 | 28 | endOfOctets = EndOfOctets() 29 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-alpine 2 | MAINTAINER Sitoi 3 | 4 | WORKDIR /dailycheckin 5 | 6 | #GitHub Actions 构建 7 | COPY ./docker/start.sh /usr/local/bin 8 | #本地构建 9 | #COPY ./start.sh /usr/local/bin 10 | 11 | RUN set -ex \ 12 | && apk update && apk upgrade\ 13 | && apk add --no-cache tzdata moreutils git gcc g++ py-pip mysql-dev linux-headers libffi-dev openssl-dev\ 14 | && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ 15 | && echo "Asia/Shanghai" > /etc/timezone \ 16 | && chmod +x /usr/local/bin/start.sh \ 17 | && git clone https://github.com/Sitoi/dailycheckin.git /dailycheckin \ 18 | && cd /dailycheckin \ 19 | && mkdir logs \ 20 | && pip install -r requirements.txt 21 | 22 | ENTRYPOINT ["start.sh"] -------------------------------------------------------------------------------- /pyasn1/compat/binary.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from sys import version_info 8 | 9 | if version_info[0:2] < (2, 6): 10 | def bin(value): 11 | bitstring = [] 12 | 13 | if value > 0: 14 | prefix = '0b' 15 | elif value < 0: 16 | prefix = '-0b' 17 | value = abs(value) 18 | else: 19 | prefix = '0b0' 20 | 21 | while value: 22 | if value & 1 == 1: 23 | bitstring.append('1') 24 | else: 25 | bitstring.append('0') 26 | 27 | value >>= 1 28 | 29 | bitstring.reverse() 30 | 31 | return prefix + ''.join(bitstring) 32 | else: 33 | bin = bin 34 | -------------------------------------------------------------------------------- /.github/workflows/repo-sync.yml: -------------------------------------------------------------------------------- 1 | # File: .github/workflows/repo-sync.yml 2 | name: 同步仓库 3 | on: 4 | schedule: 5 | - cron: '15 0 * * *' 6 | workflow_dispatch: 7 | watch: 8 | types: started 9 | repository_dispatch: 10 | types: 同步仓库 11 | jobs: 12 | repo-sync: 13 | env: 14 | PAT: ${{ secrets.PAT || github.event.client_payload.PAT }} 15 | runs-on: ubuntu-latest 16 | if: github.event.repository.owner.id == github.event.sender.id 17 | steps: 18 | - uses: actions/checkout@v2 19 | with: 20 | persist-credentials: false 21 | 22 | - name: 【同步 sitoi/dailycheckin】 23 | uses: repo-sync/github-sync@v2 24 | if: env.PAT 25 | with: 26 | source_repo: "https://github.com/Sitoi/dailycheckin.git" 27 | source_branch: "main" 28 | destination_branch: "main" 29 | github_token: ${{ secrets.PAT || github.event.client_payload.PAT }} 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/CHECKINERROR.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 反馈 3 | about: 运行 Python 脚本时出现 Bug 4 | title: '【脚本名称】具体 BUG' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 | 24 | ## 1.关于你要提交的问题 25 | 26 | Q:是否搜索了 issue(包括已关闭的issue) 27 | 28 | - [ ] 没有类似的 issue 29 | 30 | Q:是否仔细阅读了教程 31 | 32 | - [ ] 已仔细阅读教程 33 | 34 | ## 2. 你使用的哪种部署方法 35 | 36 | 37 | 38 | - [ ] 方法一:本地安装 Python 39 | - [ ] 方法二:Docker 40 | - [ ] 方法三:腾讯云函数 41 | - [ ] 方法四:GitHub Actions 42 | 43 | ## 3. 详细叙述 44 | 45 | ### (1) 具体问题 46 | 47 | A: 48 | 49 | ### (2) 详细日志 50 | 51 | A: 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sitoi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /docker_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "在当前目录下创建 config 文件夹" 4 | 5 | mkdir -p config 6 | 7 | echo "下载渲染 config 文件的脚本,并执行渲染" 8 | 9 | curl https://raw.githubusercontent.com/Sitoi/dailycheckin/main/config/config.template.json -o config/config.json 10 | 11 | docker --version 12 | if [ $? -ne 0 ];then 13 | echo "未安装 docker ,请先安装 docker 再运行脚本。" 14 | else 15 | echo "docker 环境存在,检测 docker-compose 环境是否安装..." 16 | docker-compose --version 17 | if [ $? -ne 0 ];then 18 | echo "未安装 docker-compose,将使用 docker 命令启动容器..." 19 | echo "开始通过 docker 命令创建容器" 20 | docker run -d -v $(pwd)/config:/dailycheckin/config \ 21 | -v $(pwd)/logs:/dailycheckin/logs \ 22 | --name dailycheckin \ 23 | --restart always \ 24 | sitoi/dailycheckin:latest 25 | else 26 | echo "docker-compose 环境存在,将使用 docker-compose 命令启动容器..." 27 | echo "下载 docker-compose.yml 文件" 28 | curl -O https://raw.githubusercontent.com/Sitoi/dailycheckin/main/docker/docker-compose.yml 29 | echo "下载 Makefile 文件(可以无视)" 30 | curl -O https://raw.githubusercontent.com/Sitoi/dailycheckin/main/docker/Makefile 31 | echo "开始通过 docker-compose 命令创建容器" 32 | docker-compose up -d 33 | fi 34 | fi -------------------------------------------------------------------------------- /docs/tencent-scf.md: -------------------------------------------------------------------------------- 1 | # 腾讯云函数教程 2 | 3 | ## 方式一、下载到本地修改后上传 4 | 5 | > (腾讯云函数相关教程请自行百度) 6 | 7 | ### 一、下载(Clone)本项目到本地 8 | 9 | > ⚠️ 下载的需要解压压缩包 10 | 11 | - 下载地址: [https://github.com/Sitoi/DailyCheckIn/archive/main.zip](https://github.com/Sitoi/DailyCheckIn/archive/main.zip) 12 | 13 | - Clone 地址: [https://github.com/Sitoi/dailycheckin.git](https://github.com/Sitoi/dailycheckin.git) 14 | 15 | ### 二、创建并修改 config.json 配置文件 16 | 17 | 拷贝 `config/config.template.json` 到 `config/config.json` 并修改 18 | 19 | 参考[配置说明文档](https://sitoi.github.io/dailycheckin/settings/) ,并修改 `config/config.json` 20 | 21 | ### 三、上传至【腾讯云函数】 22 | 23 | 云函数 → 函数服务 → 新建 → 自定义创建 → 本地上传文件夹 → 选择带有自定义配置文件的文件夹上传 24 | 25 | ### 四、配置定时触发器 26 | 27 | 进入函数 → 触发管理 → 新建触发器 → 安装下图进行配置 28 | 29 | ![触发器配置](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/scf_timer.png) 30 | 31 | ## 方式二、配置 Secrets 参数 基于 GitHub Action 上传致腾讯云函数 32 | 33 | ### 一、将需要签到的 cookie 账号信息填入 GitHub Actions Secrets 变量里 34 | 35 | 参考: [GitHub Actions 使用教程](https://sitoi.github.io/dailycheckin/github-actions/) 36 | 37 | ### 二、多配置腾讯云函数相关的两个参数 38 | 39 | - TENCENT_SECRET_ID 40 | - TENCENT_SECRET_KEY 41 | 42 | ### 三、运行相关的 GitHub Actions 进行部署 43 | 44 | - 根据 Secrets 配置的账号等信息自动渲染 config.json 文件 45 | - 自动将项目部署到腾讯云函数 46 | - 自动创建触发器 -------------------------------------------------------------------------------- /docs/github-actions.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions 使用教程 2 | 3 | ## 一、fork 本项目 4 | 5 | 项目地址: [https://github.com/Sitoi/dailycheckin](https://github.com/Sitoi/dailycheckin) 6 | 7 | ## 二、配置项目 Secrets 8 | 9 | ### 逐一配置 10 | 11 | > ⚠️ ️_**斜体加粗大写英文字母**_ 表示 GitHub Actions Secrets 环境变量名称,内容直接复制 _**斜体加粗大写英文字母 key**_ 对应的 value 12 | 13 | 参考[配置说明文档](https://sitoi.github.io/dailycheckin/settings/) ,`GitHub Actions Secrets` 环境变量 14 | 15 | ![Secret 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/secret.png) 16 | 17 | Secrets 填写教程,以 IQIYI_COOKIE_LIST 为例: 18 | 19 | - name: 斜体加粗大写英文字母 20 | 21 | ```text 22 | IQIYI_COOKIE_LIST 23 | ``` 24 | 25 | - value: 斜体加粗大写英文字母 对应的 value 是什么类型就填写什么类型,建议去 [http://www.json.cn](http://www.json.cn) 进行校验。 26 | 27 | ```json 28 | [ 29 | { 30 | "iqiyi_cookie": "QC005=xxxx; QC142=xxxx; T00404=xxxx; QC006=xxxx; __uuid=xxxx; QC173=0; P00004=xxxx; P00003=xxxx; P00010=xxxx; P01010=xxxx; P00PRU=xxxx" 31 | } 32 | ] 33 | ``` 34 | 35 | ### 配置整个 config.json 36 | 37 | > 如果同时配置了逐个配置,会自动合并到 CONFIG_JSON 配置中,如果全部使用 CONFIG_JSON 请删除其他的 Secrets 配置。 38 | 39 | - name: 斜体加粗大写英文字母 40 | 41 | ```text 42 | CONFIG_JSON 43 | ``` 44 | 45 | - value: config.json 配置文件全部 46 | 47 | ## 三、Star 一下,立即执行,观察运行情况 48 | 49 | 点一下自己 fork 项目的 star 立即执行 50 | 51 | ## 四、开启定时运行 52 | 53 | 必须修改一次文件(比如自己库中的 `README.md` 文件)才能定时运行 -------------------------------------------------------------------------------- /wzyd/wzyd.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | from urllib import parse 5 | 6 | import requests 7 | 8 | 9 | class WZYDCheckIn: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def sign(data): 15 | response = requests.post(url="https://ssl.kohsocialapp.qq.com:10001/play/h5sign", data=data).json() 16 | try: 17 | if response["result"] == 0: 18 | msg = "签到成功" 19 | else: 20 | msg = response["returnMsg"] 21 | except: 22 | msg = "请求失败,请检查接口" 23 | return msg 24 | 25 | def main(self): 26 | wzyd_data = self.check_item.get("wzyd_data") 27 | data = {k: v[0] for k, v in parse.parse_qs(wzyd_data).items()} 28 | try: 29 | user_id = data.get("userId", "") 30 | except Exception as e: 31 | print(f"获取用户信息失败: {e}") 32 | user_id = "未获取到用户信息" 33 | sign_msg = self.sign(data=data) 34 | msg = f"帐号信息: {user_id}\n签到信息: {sign_msg}" 35 | return msg 36 | 37 | 38 | if __name__ == "__main__": 39 | with open( 40 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 41 | ) as f: 42 | datas = json.loads(f.read()) 43 | _check_item = datas.get("WZYD_DATA_LIST", [])[0] 44 | print(WZYDCheckIn(check_item=_check_item).main()) 45 | -------------------------------------------------------------------------------- /pyasn1/compat/octets.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from sys import version_info 8 | 9 | if version_info[0] <= 2: 10 | int2oct = chr 11 | # noinspection PyPep8 12 | ints2octs = lambda s: ''.join([int2oct(x) for x in s]) 13 | null = '' 14 | oct2int = ord 15 | # TODO: refactor to return a sequence of ints 16 | # noinspection PyPep8 17 | octs2ints = lambda s: [oct2int(x) for x in s] 18 | # noinspection PyPep8 19 | str2octs = lambda x: x 20 | # noinspection PyPep8 21 | octs2str = lambda x: x 22 | # noinspection PyPep8 23 | isOctetsType = lambda s: isinstance(s, str) 24 | # noinspection PyPep8 25 | isStringType = lambda s: isinstance(s, (str, unicode)) 26 | # noinspection PyPep8 27 | ensureString = str 28 | else: 29 | ints2octs = bytes 30 | # noinspection PyPep8 31 | int2oct = lambda x: ints2octs((x,)) 32 | null = ints2octs() 33 | # noinspection PyPep8 34 | oct2int = lambda x: x 35 | # noinspection PyPep8 36 | octs2ints = lambda x: x 37 | # noinspection PyPep8 38 | str2octs = lambda x: x.encode('iso-8859-1') 39 | # noinspection PyPep8 40 | octs2str = lambda x: x.decode('iso-8859-1') 41 | # noinspection PyPep8 42 | isOctetsType = lambda s: isinstance(s, bytes) 43 | # noinspection PyPep8 44 | isStringType = lambda s: isinstance(s, str) 45 | # noinspection PyPep8 46 | ensureString = bytes 47 | -------------------------------------------------------------------------------- /docs/synology.md: -------------------------------------------------------------------------------- 1 | # 群晖 Docker 使用教程 2 | 3 | ## 一、注册表搜索 sitoi 或者 dailycheckin , 双击下载 4 | 5 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology1.jpg) 6 | 7 | 如果注册表储存库没找到,请添加 Docker Hub 库地址:https://registry.hub.docker.com 8 | 9 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology2.jpg) 10 | 11 | ## 二、映像 下载完成 双击或者点击启动开始创建 12 | 13 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology3.jpg) 14 | 15 | 点击高级设置,设置卷,按照下图添加文件夹和装载路径 16 | 17 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology4.jpg) 18 | 19 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology5.jpg) 20 | 21 | 群晖内本地文件夹请自行创建 22 | 23 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology6.jpg) 24 | 25 | ```text 26 | . 27 | |-- config 28 | | `-- config.json 29 | |-- docker-compose.yml 30 | |-- logs 31 | | `-- default_task.log 32 | `-- Makefile 33 | ``` 34 | 35 | 如图,设置好直接点应用,其他默认,可按需点击高级设置里的启用自动重新启动,以防机器意外重启出现脚本停止现象。 36 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology7.jpg) 37 | 38 | ## 三、回到容器,如图即是运行成功 39 | 40 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology8.jpg) 41 | 42 | ## 四:配置测试 43 | 44 | 1、双击容器查看进程,如下图说明正在运行 45 | 46 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology9.jpg) 47 | 48 | 2、日志查看运行状态 49 | 50 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology10.jpg) 51 | 52 | 3、执行脚本之后自动生成的脚本 53 | 54 | ![获取 cookie 教程](https://cdn.jsdelivr.net/gh/Sitoi/dailycheckin/docs/img/synology11.jpg) 55 | -------------------------------------------------------------------------------- /rsa/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """RSA module 15 | 16 | Module for calculating large primes, and RSA encryption, decryption, signing 17 | and verification. Includes generating public and private keys. 18 | 19 | WARNING: this implementation does not use compression of the cleartext input to 20 | prevent repetitions, or other common security improvements. Use with care. 21 | 22 | """ 23 | 24 | from rsa.key import PrivateKey, PublicKey, newkeys 25 | from rsa.pkcs1 import DecryptionError, VerificationError, compute_hash, decrypt, encrypt, find_signature_hash, sign, \ 26 | sign_hash, verify 27 | 28 | __author__ = "Sybren Stuvel, Barry Mead and Yesudeep Mangalapilly" 29 | __date__ = '2020-06-12' 30 | __version__ = '4.6' 31 | 32 | # Do doctest if we're run directly 33 | if __name__ == "__main__": 34 | import doctest 35 | 36 | doctest.testmod() 37 | 38 | __all__ = ["newkeys", "encrypt", "decrypt", "sign", "verify", 'PublicKey', 39 | 'PrivateKey', 'DecryptionError', 'VerificationError', 40 | 'find_signature_hash', 'compute_hash', 'sign_hash'] 41 | -------------------------------------------------------------------------------- /rsa/_compat.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Python compatibility wrappers.""" 16 | 17 | from struct import pack 18 | 19 | 20 | def byte(num: int) -> bytes: 21 | """ 22 | Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) 23 | representation. 24 | 25 | :param num: 26 | An unsigned integer between 0 and 255 (both inclusive). 27 | :returns: 28 | A single byte. 29 | """ 30 | return pack("B", num) 31 | 32 | 33 | def xor_bytes(b1: bytes, b2: bytes) -> bytes: 34 | """ 35 | Returns the bitwise XOR result between two bytes objects, b1 ^ b2. 36 | 37 | Bitwise XOR operation is commutative, so order of parameters doesn't 38 | generate different results. If parameters have different length, extra 39 | length of the largest one is ignored. 40 | 41 | :param b1: 42 | First bytes object. 43 | :param b2: 44 | Second bytes object. 45 | :returns: 46 | Bytes object, result of XOR operation. 47 | """ 48 | return bytes(x ^ y for x, y in zip(b1, b2)) 49 | -------------------------------------------------------------------------------- /rsa/core.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Core mathematical operations. 16 | 17 | This is the actual core RSA implementation, which is only defined 18 | mathematically on integers. 19 | """ 20 | 21 | 22 | def assert_int(var: int, name: str) -> None: 23 | if isinstance(var, int): 24 | return 25 | 26 | raise TypeError('%s should be an integer, not %s' % (name, var.__class__)) 27 | 28 | 29 | def encrypt_int(message: int, ekey: int, n: int) -> int: 30 | """Encrypts a message using encryption key 'ekey', working modulo n""" 31 | 32 | assert_int(message, 'message') 33 | assert_int(ekey, 'ekey') 34 | assert_int(n, 'n') 35 | 36 | if message < 0: 37 | raise ValueError('Only non-negative numbers are supported') 38 | 39 | if message > n: 40 | raise OverflowError("The message %i is too long for n=%i" % (message, n)) 41 | 42 | return pow(message, ekey, n) 43 | 44 | 45 | def decrypt_int(cyphertext: int, dkey: int, n: int) -> int: 46 | """Decrypts a cypher text using the decryption key 'dkey', working modulo n""" 47 | 48 | assert_int(cyphertext, 'cyphertext') 49 | assert_int(dkey, 'dkey') 50 | assert_int(n, 'n') 51 | 52 | message = pow(cyphertext, dkey, n) 53 | return message 54 | -------------------------------------------------------------------------------- /docs/docker.md: -------------------------------------------------------------------------------- 1 | # Docker 使用教程 2 | 3 | ## 一、运行如下命令一键启动并创建服务 4 | 5 | ```bash 6 | curl https://raw.githubusercontent.com/Sitoi/dailycheckin/main/docker_start.sh | bash 7 | ``` 8 | 9 | 国内源: 10 | 11 | ```bash 12 | curl https://gitee.com/sitoi/dailycheckin/raw/main/docker_start.sh | bash 13 | ``` 14 | 15 | > 运行成功会自动创建如下目录结构, 并成功启动 docker 服务。 16 | 17 | ```text 18 | . 19 | |-- config 20 | | `-- config.json 21 | |-- docker-compose.yml 22 | |-- logs 23 | | `-- default_task.log 24 | `-- Makefile 25 | ``` 26 | 27 | - `./config/config.json`: 配置文件 28 | - `./docker-compose.yml`: docker 启动文件(只在有 docker-compose 的情况下创建) 29 | - `./logs`: 日志文件 30 | - `./Makefile`: make 脚本命令(只在有 docker-compose 的情况下创建) 31 | 32 | ## 二、修改配置文件 33 | 34 | 文件路径: `./config/config.json` 35 | 36 | > ⚠️ ️请务必到 [http://www.json.cn](http://www.json.cn) 网站检查 `config.json` 文件格式是否正确! 37 | 38 | 参考 [配置说明文档](https://sitoi.github.io/dailycheckin/settings/) ,并修改 `config.json` 39 | 40 | ## 三、立即执行单次签到(确保容器已启动),检查 config.json 是否配置正确 41 | 42 | ##### 运行【日常签到类】(除喜马拉雅极速版) 43 | 44 | ```bash 45 | docker exec dailycheckin python3 index.py 46 | ``` 47 | 48 | ##### 更新最新脚本 49 | 50 | ```bash 51 | docker exec dailycheckin sh /dailycheckin/docker/default_task.sh 52 | ``` 53 | 54 | ## 附录 55 | 56 | ### docker-compose 安装 57 | 58 | ##### 方式一(Python 环境) 59 | 60 | ```bash 61 | pip3 install docker-compose 62 | ``` 63 | 64 | ##### 方式二 65 | 66 | ``` 67 | sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 68 | sudo chmod +x /usr/local/bin/docker-compose 69 | ``` 70 | 71 | 通过 `docker-compose version` 查看 `docker-compose` 版本,确认是否安装成功。 72 | 73 | ### docker-compose 常用命令 74 | 75 | - `docker-compose logs` 打印日志 76 | - `docker-compose pull` 更新镜像 77 | - `docker-compose stop` 停止容器 78 | - `docker-compose restart` 重启容器 79 | - `docker-compose down` 停止并删除容器 80 | - `docker exec -it dailycheckin sh` 进入 docker 81 | -------------------------------------------------------------------------------- /weather/weather.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | from datetime import datetime 5 | 6 | import requests 7 | 8 | 9 | class Weather: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | def main(self): 14 | """ 15 | 获取天气信息。网址:https://www.sojson.com/blog/305.html 16 | :return: 17 | """ 18 | with open(os.path.join(os.path.dirname(__file__), "city.json"), "r", encoding="utf-8") as city_file: 19 | city_map = json.loads(city_file.read()) 20 | city_code = city_map.get(self.check_item, "101020100") 21 | weather_url = f"http://t.weather.itboy.net/api/weather/city/{city_code}" 22 | today_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 23 | resp = requests.get(url=weather_url) 24 | if resp.status_code == 200 and resp.json().get("status") == 200: 25 | weather_json = resp.json() 26 | today_weather = weather_json.get("data").get("forecast")[1] 27 | notice = today_weather.get("notice") 28 | high = today_weather.get("high") 29 | low = today_weather.get("low") 30 | temperature = f"温度: {low[low.find(' ') + 1:]}/{high[high.find(' ') + 1:]}" 31 | wind = f"{today_weather.get('fx')}: {today_weather.get('fl')}" 32 | aqi = f"空气: {today_weather.get('aqi')}" 33 | msg = f"城市: {self.check_item}\n时间: {today_time}\n{notice}\n{temperature}\n{wind}\n{aqi}\n" 34 | else: 35 | msg = f"城市: {self.check_item}\n时间: {today_time}天气情况: 获取失败" 36 | return msg 37 | 38 | 39 | if __name__ == "__main__": 40 | with open( 41 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 42 | ) as f: 43 | datas = json.loads(f.read()) 44 | _check_item = datas.get("CITY_NAME_LIST")[0] 45 | print(Weather(check_item=_check_item).main()) 46 | -------------------------------------------------------------------------------- /rsa/asn1.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ASN.1 definitions. 16 | 17 | Not all ASN.1-handling code use these definitions, but when it does, they should be here. 18 | """ 19 | 20 | from pyasn1.type import univ, namedtype, tag 21 | 22 | 23 | class PubKeyHeader(univ.Sequence): 24 | componentType = namedtype.NamedTypes( 25 | namedtype.NamedType('oid', univ.ObjectIdentifier()), 26 | namedtype.NamedType('parameters', univ.Null()), 27 | ) 28 | 29 | 30 | class OpenSSLPubKey(univ.Sequence): 31 | componentType = namedtype.NamedTypes( 32 | namedtype.NamedType('header', PubKeyHeader()), 33 | 34 | # This little hack (the implicit tag) allows us to get a Bit String as Octet String 35 | namedtype.NamedType('key', univ.OctetString().subtype( 36 | implicitTag=tag.Tag(tagClass=0, tagFormat=0, tagId=3))), 37 | ) 38 | 39 | 40 | class AsnPubKey(univ.Sequence): 41 | """ASN.1 contents of DER encoded public key: 42 | 43 | RSAPublicKey ::= SEQUENCE { 44 | modulus INTEGER, -- n 45 | publicExponent INTEGER, -- e 46 | """ 47 | 48 | componentType = namedtype.NamedTypes( 49 | namedtype.NamedType('modulus', univ.Integer()), 50 | namedtype.NamedType('publicExponent', univ.Integer()), 51 | ) 52 | -------------------------------------------------------------------------------- /baidu_url_submit/baidu_url_submit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | from urllib import parse 5 | 6 | import requests 7 | 8 | 9 | class BaiduUrlSubmit: 10 | def __init__(self, check_item: dict): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def url_submit(data_url: str, submit_url: str, times: int = 100) -> str: 15 | site = parse.parse_qs(parse.urlsplit(submit_url).query).get("site")[0] 16 | urls_data = requests.get(url=data_url) 17 | remian = 100000 18 | success_count = 0 19 | error_count = 0 20 | for one in range(times): 21 | try: 22 | response = requests.post(url=submit_url, data=urls_data) 23 | if response.json().get("success"): 24 | remian = response.json().get("remain") 25 | success_count += response.json().get("success") 26 | else: 27 | error_count += 1 28 | except Exception as e: 29 | print(e) 30 | error_count += 1 31 | msg = ( 32 | f"站点地址: {site}\n当天剩余的可推送 url 条数: {remian}\n成功推送的 url 条数: {success_count}\n" 33 | f"成功推送的 url 次数: {times - error_count}\n失败推送的 url 次数: {error_count}" 34 | ) 35 | return msg 36 | 37 | def main(self): 38 | data_url = self.check_item.get("data_url") 39 | submit_url = self.check_item.get("submit_url") 40 | times = int(self.check_item.get("times", 100)) 41 | if data_url and submit_url: 42 | msg = self.url_submit(data_url=data_url, submit_url=submit_url, times=times) 43 | else: 44 | msg = "配置错误" 45 | return msg 46 | 47 | 48 | if __name__ == "__main__": 49 | with open( 50 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 51 | ) as f: 52 | datas = json.loads(f.read()) 53 | _check_item = datas.get("BAIDU_URL_SUBMIT_LIST", [])[0] 54 | print(BaiduUrlSubmit(check_item=_check_item).main()) 55 | -------------------------------------------------------------------------------- /csdn/csdn.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | import requests 6 | 7 | 8 | class CSDNCheckIn: 9 | def __init__(self, check_item): 10 | self.check_item = check_item 11 | self.headers = { 12 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74", 13 | } 14 | 15 | def sign(self, cookies): 16 | response = requests.get( 17 | url="https://me.csdn.net/api/LuckyDraw_v2/signIn", headers=self.headers, cookies=cookies 18 | ).json() 19 | if response.get("code") == 200: 20 | msg = response.get("data").get("msg") 21 | else: 22 | msg = "签到失败" 23 | print(response) 24 | return msg 25 | 26 | def draw(self, cookies): 27 | response = requests.get( 28 | url="https://me.csdn.net/api/LuckyDraw_v2/goodluck", headers=self.headers, cookies=cookies 29 | ).json() 30 | if response.get("code") == 200: 31 | msg = response.get("data").get("msg") 32 | else: 33 | msg = "抽奖失败" 34 | return msg 35 | 36 | def main(self): 37 | csdn_cookie = { 38 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("csdn_cookie").split("; ") 39 | } 40 | try: 41 | user_name = csdn_cookie.get("UserName", "") 42 | except Exception as e: 43 | print(f"获取用户信息失败: {e}") 44 | user_name = "未获取到用户信息" 45 | sign_msg = self.sign(cookies=csdn_cookie) 46 | draw_msg = self.draw(cookies=csdn_cookie) 47 | msg = f"帐号信息: {user_name}\n签到信息: {sign_msg}\n抽奖结果: {draw_msg}" 48 | return msg 49 | 50 | 51 | if __name__ == "__main__": 52 | with open( 53 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 54 | ) as f: 55 | datas = json.loads(f.read()) 56 | _check_item = datas.get("CSDN_COOKIE_LIST", [])[0] 57 | print(CSDNCheckIn(check_item=_check_item).main()) 58 | -------------------------------------------------------------------------------- /pojie/pojie.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | 8 | 9 | class PojieCheckIn: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def sign(headers): 15 | msg = "" 16 | try: 17 | session = requests.session() 18 | session.get(url="https://www.52pojie.cn/home.php?mod=task&do=apply&id=2", headers=headers) 19 | resp = session.get(url="https://www.52pojie.cn/home.php?mod=task&do=draw&id=2", headers=headers) 20 | content = re.findall(r'
(.*?)

', resp.text)[0] 21 | if "您需要先登录才能继续本操作" in resp.text: 22 | msg += "吾爱破解 cookie 失效" 23 | elif "安域防护节点" in resp.text: 24 | msg += "触发吾爱破解安全防护,访问出错。自行修改脚本运行时间和次数,总有能访问到的时间" 25 | elif "恭喜" in resp.text: 26 | msg += "吾爱破解签到成功" 27 | else: 28 | msg += content 29 | except Exception as e: 30 | print("签到错误", e) 31 | msg += "吾爱破解出错" 32 | return msg 33 | 34 | def main(self): 35 | pojie_cookie = self.check_item.get("pojie_cookie") 36 | headers = { 37 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36", 38 | "Cookie": pojie_cookie, 39 | "ContentType": "text/html;charset=gbk", 40 | } 41 | try: 42 | uid = re.findall(r"htVD_2132_lastcheckfeed=(.*?);", pojie_cookie)[0].split("%7C")[0] 43 | except Exception as e: 44 | print(e) 45 | uid = "未获取到用户 uid" 46 | sign_msg = self.sign(headers=headers) 47 | msg = f"帐号信息: {uid}\n签到状态: {sign_msg}" 48 | return msg 49 | 50 | 51 | if __name__ == "__main__": 52 | with open( 53 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 54 | ) as f: 55 | datas = json.loads(f.read()) 56 | _check_item = datas.get("POJIE_COOKIE_LIST", [])[0] 57 | print(PojieCheckIn(check_item=_check_item).main()) 58 | -------------------------------------------------------------------------------- /mgtv/mgtv.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import time 5 | from urllib import parse 6 | 7 | import requests 8 | 9 | 10 | class MgtvCheckIn: 11 | def __init__(self, check_item): 12 | self.check_item = check_item 13 | 14 | @staticmethod 15 | def sign(params): 16 | url = "https://credits.bz.mgtv.com/user/creditsTake" 17 | user_params = { 18 | "abroad": params.get("abroad"), 19 | "ageMode": "0", 20 | "appVersion": params.get("appVersion"), 21 | "artistId": params.get("uuid"), 22 | "device": params.get("device"), 23 | "did": params.get("did"), 24 | "mac": params.get("did"), 25 | "osType": params.get("osType"), 26 | "src": "mgtv", 27 | "testversion": "", 28 | "ticket": params.get("ticket"), 29 | "uuid": params.get("uuid"), 30 | } 31 | try: 32 | user_info = requests.get(url="https://homepage.bz.mgtv.com/v2/user/userInfo", params=user_params).json() 33 | username = user_info.get("data", {}).get("nickName") 34 | except Exception as e: 35 | print("获取用户信息失败", e) 36 | username = params.get("uuid") 37 | res = requests.get(url=url, params=params) 38 | res_json = json.loads(res.text.replace(f"{params.get('callback')}(", "").replace(");", "")) 39 | if res_json["code"] == 200: 40 | cur_day = res_json["data"]["curDay"] 41 | _credits = res_json["data"]["credits"] 42 | msg = f"帐号信息: {username}\n签到积分: +{_credits}积分\n已经签到: {cur_day}天/21天" 43 | else: 44 | msg = f"帐号信息: {username}\n签到状态: 已完成签到 or 签到失败" 45 | return msg 46 | 47 | def main(self): 48 | mgtv_params = self.check_item.get("mgtv_params") 49 | params = parse.parse_qs(mgtv_params) 50 | params["timestamp"] = [round(time.time())] 51 | params = {key: value[0] for key, value in params.items()} 52 | msg = self.sign(params=params) 53 | return msg 54 | 55 | 56 | if __name__ == "__main__": 57 | with open( 58 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 59 | ) as f: 60 | datas = json.loads(f.read()) 61 | _check_item = datas.get("MGTV_PARAMS_LIST", [])[0] 62 | print(MgtvCheckIn(check_item=_check_item).main()) 63 | -------------------------------------------------------------------------------- /youdao/youdao.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | import requests 6 | 7 | 8 | class YouDaoCheckIn: 9 | def __init__(self, check_item): 10 | self.check_item = check_item 11 | 12 | @staticmethod 13 | def sign(cookies): 14 | ad_space = 0 15 | refresh_cookies_res = requests.get("http://note.youdao.com/login/acc/pe/getsess?product=YNOTE", cookies=cookies) 16 | cookies = dict(refresh_cookies_res.cookies) 17 | url = "https://note.youdao.com/yws/api/daupromotion?method=sync" 18 | res = requests.post(url=url, cookies=cookies) 19 | if "error" not in res.text: 20 | checkin_response = requests.post( 21 | url="https://note.youdao.com/yws/mapi/user?method=checkin", cookies=cookies 22 | ) 23 | for i in range(3): 24 | ad_response = requests.post( 25 | url="https://note.youdao.com/yws/mapi/user?method=adRandomPrompt", cookies=cookies 26 | ) 27 | ad_space += ad_response.json().get("space", 0) // 1048576 28 | if "reward" in res.text: 29 | sync_space = res.json().get("rewardSpace", 0) // 1048576 30 | checkin_space = checkin_response.json().get("space", 0) // 1048576 31 | space = sync_space + checkin_space + ad_space 32 | youdao_message = "+{0}M".format(space) 33 | else: 34 | youdao_message = "获取失败" 35 | else: 36 | youdao_message = "Cookie 可能过期" 37 | return youdao_message 38 | 39 | def main(self): 40 | youdao_cookie = { 41 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("youdao_cookie").split("; ") 42 | } 43 | try: 44 | ynote_pers = youdao_cookie.get("YNOTE_PERS", "") 45 | uid = ynote_pers.split("||")[-2] 46 | except Exception as e: 47 | print(f"获取用户信息失败: {e}") 48 | uid = "未获取到用户信息" 49 | msg = self.sign(cookies=youdao_cookie) 50 | msg = f"帐号信息: {uid}\n获取空间: {msg}" 51 | return msg 52 | 53 | 54 | if __name__ == "__main__": 55 | with open( 56 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 57 | ) as f: 58 | datas = json.loads(f.read()) 59 | _check_item = datas.get("YOUDAO_COOKIE_LIST", [])[0] 60 | print(YouDaoCheckIn(check_item=_check_item).main()) 61 | -------------------------------------------------------------------------------- /rsa/transform.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Data transformation functions. 16 | 17 | From bytes to a number, number to bytes, etc. 18 | """ 19 | 20 | import math 21 | 22 | 23 | def bytes2int(raw_bytes: bytes) -> int: 24 | r"""Converts a list of bytes or an 8-bit string to an integer. 25 | 26 | When using unicode strings, encode it to some encoding like UTF8 first. 27 | 28 | >>> (((128 * 256) + 64) * 256) + 15 29 | 8405007 30 | >>> bytes2int(b'\x80@\x0f') 31 | 8405007 32 | 33 | """ 34 | return int.from_bytes(raw_bytes, 'big', signed=False) 35 | 36 | 37 | def int2bytes(number: int, fill_size: int = 0) -> bytes: 38 | """ 39 | Convert an unsigned integer to bytes (big-endian):: 40 | 41 | Does not preserve leading zeros if you don't specify a fill size. 42 | 43 | :param number: 44 | Integer value 45 | :param fill_size: 46 | If the optional fill size is given the length of the resulting 47 | byte string is expected to be the fill size and will be padded 48 | with prefix zero bytes to satisfy that length. 49 | :returns: 50 | Raw bytes (base-256 representation). 51 | :raises: 52 | ``OverflowError`` when fill_size is given and the number takes up more 53 | bytes than fit into the block. This requires the ``overflow`` 54 | argument to this function to be set to ``False`` otherwise, no 55 | error will be raised. 56 | """ 57 | 58 | if number < 0: 59 | raise ValueError("Number must be an unsigned integer: %d" % number) 60 | 61 | bytes_required = max(1, math.ceil(number.bit_length() / 8)) 62 | 63 | if fill_size > 0: 64 | return number.to_bytes(fill_size, 'big') 65 | 66 | return number.to_bytes(bytes_required, 'big') 67 | 68 | 69 | if __name__ == '__main__': 70 | import doctest 71 | 72 | doctest.testmod() 73 | -------------------------------------------------------------------------------- /index.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import time 5 | from datetime import datetime, timedelta 6 | 7 | from config import checkin_map, env2config, get_checkin_info, get_notice_info 8 | from motto import Motto 9 | from utils.message import push_message 10 | 11 | 12 | def main_handler(event, context): 13 | start_time = time.time() 14 | utc_time = datetime.utcnow() + timedelta(hours=8) 15 | if "IS_GITHUB_ACTION" in os.environ: 16 | data = env2config() 17 | else: 18 | with open(os.path.join(os.path.dirname(__file__), "config/config.json"), "r", encoding="utf-8") as f: 19 | data = json.loads(f.read()) 20 | try: 21 | motto = data.get("MOTTO") 22 | notice_info = get_notice_info(data=data) 23 | check_info = get_checkin_info(data=data) 24 | except Exception as e: 25 | raise e 26 | content_list = [f"当前时间: {utc_time}"] 27 | for one_check, check_tuple in checkin_map.items(): 28 | check_name, check_func = check_tuple 29 | if check_info.get(one_check.lower()): 30 | print(f"----------已检测到正确的配置,并开始执行【{check_name}】签到----------") 31 | for index, check_item in enumerate(check_info.get(one_check.lower(), [])): 32 | print(f"----------开始执行【{check_name}】签到 : 第 {index + 1} 个账号----------") 33 | if "xxxxxx" not in str(check_item) and "多账号" not in str(check_item): 34 | try: 35 | msg = check_func(check_item).main() 36 | content_list.append(f"【{check_name}】\n{msg}") 37 | print(f"----------执行完成 【{check_name}】签到 : 第 {index + 1} 个账号----------") 38 | except Exception as e: 39 | content_list.append(f"【{check_name}】\n{e}") 40 | print(f"----------执行失败 【{check_name}】签到 : 错误日志如下:----------\n{e}") 41 | 42 | else: 43 | print(f"----------跳过执行【{check_name}】签到 : 配置文件包含自带的默认配置----------") 44 | else: 45 | print(f"----------未检测到正确的配置,并跳过执行【{check_name}】签到----------") 46 | if motto: 47 | try: 48 | msg_list = Motto().main() 49 | except Exception as e: 50 | print(e) 51 | msg_list = [] 52 | content_list += msg_list 53 | content_list.append(f"任务使用时间: {int(time.time() - start_time)} 秒") 54 | push_message(content_list=content_list, notice_info=notice_info) 55 | return 56 | 57 | 58 | if __name__ == "__main__": 59 | main_handler(event=None, context=None) 60 | -------------------------------------------------------------------------------- /pyasn1/error.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | 8 | 9 | class PyAsn1Error(Exception): 10 | """Base pyasn1 exception 11 | 12 | `PyAsn1Error` is the base exception class (based on 13 | :class:`Exception`) that represents all possible ASN.1 related 14 | errors. 15 | """ 16 | 17 | 18 | class ValueConstraintError(PyAsn1Error): 19 | """ASN.1 type constraints violation exception 20 | 21 | The `ValueConstraintError` exception indicates an ASN.1 value 22 | constraint violation. 23 | 24 | It might happen on value object instantiation (for scalar types) or on 25 | serialization (for constructed types). 26 | """ 27 | 28 | 29 | class SubstrateUnderrunError(PyAsn1Error): 30 | """ASN.1 data structure deserialization error 31 | 32 | The `SubstrateUnderrunError` exception indicates insufficient serialised 33 | data on input of a de-serialization codec. 34 | """ 35 | 36 | 37 | class PyAsn1UnicodeError(PyAsn1Error, UnicodeError): 38 | """Unicode text processing error 39 | 40 | The `PyAsn1UnicodeError` exception is a base class for errors relating to 41 | unicode text de/serialization. 42 | 43 | Apart from inheriting from :class:`PyAsn1Error`, it also inherits from 44 | :class:`UnicodeError` to help the caller catching unicode-related errors. 45 | """ 46 | def __init__(self, message, unicode_error=None): 47 | if isinstance(unicode_error, UnicodeError): 48 | UnicodeError.__init__(self, *unicode_error.args) 49 | PyAsn1Error.__init__(self, message) 50 | 51 | 52 | class PyAsn1UnicodeDecodeError(PyAsn1UnicodeError, UnicodeDecodeError): 53 | """Unicode text decoding error 54 | 55 | The `PyAsn1UnicodeDecodeError` exception represents a failure to 56 | deserialize unicode text. 57 | 58 | Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits 59 | from :class:`UnicodeDecodeError` to help the caller catching unicode-related 60 | errors. 61 | """ 62 | 63 | 64 | class PyAsn1UnicodeEncodeError(PyAsn1UnicodeError, UnicodeEncodeError): 65 | """Unicode text encoding error 66 | 67 | The `PyAsn1UnicodeEncodeError` exception represents a failure to 68 | serialize unicode text. 69 | 70 | Apart from inheriting from :class:`PyAsn1UnicodeError`, it also inherits 71 | from :class:`UnicodeEncodeError` to help the caller catching 72 | unicode-related errors. 73 | """ 74 | 75 | 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 97 | __pypackages__/ 98 | 99 | # Celery stuff 100 | celerybeat-schedule 101 | celerybeat.pid 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | .idea 133 | config.json -------------------------------------------------------------------------------- /rsa/parallel.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Functions for parallel computation on multiple cores. 16 | 17 | Introduced in Python-RSA 3.1. 18 | 19 | .. note:: 20 | 21 | Requires Python 2.6 or newer. 22 | 23 | """ 24 | 25 | import multiprocessing as mp 26 | from multiprocessing.connection import Connection 27 | 28 | import rsa.prime 29 | import rsa.randnum 30 | 31 | 32 | def _find_prime(nbits: int, pipe: Connection) -> None: 33 | while True: 34 | integer = rsa.randnum.read_random_odd_int(nbits) 35 | 36 | # Test for primeness 37 | if rsa.prime.is_prime(integer): 38 | pipe.send(integer) 39 | return 40 | 41 | 42 | def getprime(nbits: int, poolsize: int) -> int: 43 | """Returns a prime number that can be stored in 'nbits' bits. 44 | 45 | Works in multiple threads at the same time. 46 | 47 | >>> p = getprime(128, 3) 48 | >>> rsa.prime.is_prime(p-1) 49 | False 50 | >>> rsa.prime.is_prime(p) 51 | True 52 | >>> rsa.prime.is_prime(p+1) 53 | False 54 | 55 | >>> from rsa import common 56 | >>> common.bit_size(p) == 128 57 | True 58 | 59 | """ 60 | 61 | (pipe_recv, pipe_send) = mp.Pipe(duplex=False) 62 | 63 | # Create processes 64 | try: 65 | procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send)) 66 | for _ in range(poolsize)] 67 | # Start processes 68 | for p in procs: 69 | p.start() 70 | 71 | result = pipe_recv.recv() 72 | finally: 73 | pipe_recv.close() 74 | pipe_send.close() 75 | 76 | # Terminate processes 77 | for p in procs: 78 | p.terminate() 79 | 80 | return result 81 | 82 | 83 | __all__ = ['getprime'] 84 | 85 | if __name__ == '__main__': 86 | print('Running doctests 1000x or until failure') 87 | import doctest 88 | 89 | for count in range(100): 90 | (failures, tests) = doctest.testmod() 91 | if failures: 92 | break 93 | 94 | if count % 10 == 0 and count: 95 | print('%i times' % count) 96 | 97 | print('Doctests done') 98 | -------------------------------------------------------------------------------- /www2nzz/www2nzz.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | import urllib3 8 | from requests import utils 9 | 10 | urllib3.disable_warnings() 11 | 12 | 13 | class WWW2nzzCheckIn: 14 | def __init__(self, check_item): 15 | self.check_item = check_item 16 | 17 | @staticmethod 18 | def sign(session): 19 | response = session.get(url="http://www.2nzz.com/index.php", verify=False) 20 | formhash = re.findall(r'(.*?)
", response.text, re.S) 37 | check_msg = check_msg[0].strip() if check_msg else "签到失败" 38 | msg = f"用户信息: {uid}\n签到信息: {check_msg}" 39 | return msg 40 | 41 | def main(self): 42 | www2nzz_cookie = { 43 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("www2nzz_cookie").split("; ") 44 | } 45 | session = requests.session() 46 | requests.utils.add_dict_to_cookiejar(session.cookies, www2nzz_cookie) 47 | session.headers.update( 48 | { 49 | "Origin": "http://www.2nzz.com", 50 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74", 51 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 52 | "Referer": "http://www.2nzz.com/index.php", 53 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 54 | } 55 | ) 56 | msg = self.sign(session=session) 57 | return msg 58 | 59 | 60 | if __name__ == "__main__": 61 | with open( 62 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 63 | ) as f: 64 | datas = json.loads(f.read()) 65 | _check_item = datas.get("WWW2NZZ_COOKIE_LIST", [])[0] 66 | print(WWW2nzzCheckIn(check_item=_check_item).main()) 67 | -------------------------------------------------------------------------------- /zhiyoo/zhiyoo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | import urllib3 8 | from requests import utils 9 | 10 | urllib3.disable_warnings() 11 | 12 | 13 | class ZhiyooCheckIn: 14 | def __init__(self, check_item): 15 | self.check_item = check_item 16 | 17 | @staticmethod 18 | def sign(session): 19 | response = session.get(url="http://bbs.zhiyoo.net/plugin.php?id=dsu_paulsign:sign", verify=False) 20 | formhash = re.findall(r'/dev/null 2>&1; then 16 | echo 'moreutils tools installed, default task append |ts output' 17 | echo '系统已安装 moreutils 工具包,默认定时任务增加|ts 输出' 18 | ##复制一个新文件来追加|ts,防止git pull的时候冲突 19 | cp $defaultListFile /dailycheckin/docker/crontab_list.sh 20 | defaultListFile="/dailycheckin/docker/crontab_list.sh" 21 | 22 | sed -i 's/>>/|ts >>/g' $defaultListFile 23 | fi 24 | 25 | if [ $CUSTOM_LIST_FILE ]; then 26 | echo "You have configured a custom list file: $CUSTOM_LIST_FILE, custom list merge type: $CUSTOM_LIST_MERGE_TYPE..." 27 | echo "您配置了自定义任务文件:$CUSTOM_LIST_FILE,自定义任务类型为:$CUSTOM_LIST_MERGE_TYPE..." 28 | if [ -f "$customListFile" ]; then 29 | if [ $CUSTOM_LIST_MERGE_TYPE == "append" ]; then 30 | echo "merge default list file: $DEFAULT_LIST_FILE and custom list file: $CUSTOM_LIST_FILE" 31 | echo "合并默认定时任务文件:$DEFAULT_LIST_FILE 和 自定义定时任务文件:$CUSTOM_LIST_FILE" 32 | cat $defaultListFile >$mergedListFile 33 | echo -e "" >>$mergedListFile 34 | cat $customListFile >>$mergedListFile 35 | elif [ $CUSTOM_LIST_MERGE_TYPE == "overwrite" ]; then 36 | cat $customListFile >$mergedListFile 37 | echo "merge custom list file: $CUSTOM_LIST_FILE..." 38 | echo "合并自定义任务文件:$CUSTOM_LIST_FILE" 39 | touch "$customListFile" 40 | else 41 | echo "配置配置了错误的自定义定时任务类型:$CUSTOM_LIST_MERGE_TYPE,自定义任务类型为只能为append或者overwrite..." 42 | cat $defaultListFile >$mergedListFile 43 | fi 44 | else 45 | echo "Not found custom list file: $CUSTOM_LIST_FILE ,use default list file: $DEFAULT_LIST_FILE" 46 | echo "自定义任务文件:$CUSTOM_LIST_FILE 未找到,使用默认配置$DEFAULT_LIST_FILE..." 47 | cat $defaultListFile >$mergedListFile 48 | fi 49 | else 50 | echo "The currently used is the default crontab task file: $DEFAULT_LIST_FILE ..." 51 | echo "当前使用的为默认定时任务文件 $DEFAULT_LIST_FILE ..." 52 | cat $defaultListFile >$mergedListFile 53 | fi 54 | 55 | # 判断最后要加载的定时任务是否包含默认定时任务,不包含的话就加进去 56 | if [ $(grep -c "default_task.sh" $mergedListFile) -eq '0' ]; then 57 | echo "Merged crontab task file,the required default task is not included, append default task..." 58 | echo "合并后的定时任务文件,未包含必须的默认定时任务,增加默认定时任务..." 59 | echo -e >>$mergedListFile 60 | echo "0 */12 * * * sh /dailycheckin/docker/default_task.sh >> /dailycheckin/logs/default_task.log 2>&1" >>$mergedListFile 61 | fi 62 | 63 | echo "Load the latest crontab task file..." 64 | echo "加载最新的定时任务文件..." 65 | crontab $mergedListFile 66 | -------------------------------------------------------------------------------- /rsa/randnum.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Functions for generating random numbers.""" 16 | 17 | # Source inspired by code by Yesudeep Mangalapilly 18 | 19 | import os 20 | import struct 21 | 22 | from rsa import common, transform 23 | 24 | 25 | def read_random_bits(nbits: int) -> bytes: 26 | """Reads 'nbits' random bits. 27 | 28 | If nbits isn't a whole number of bytes, an extra byte will be appended with 29 | only the lower bits set. 30 | """ 31 | 32 | nbytes, rbits = divmod(nbits, 8) 33 | 34 | # Get the random bytes 35 | randomdata = os.urandom(nbytes) 36 | 37 | # Add the remaining random bits 38 | if rbits > 0: 39 | randomvalue = ord(os.urandom(1)) 40 | randomvalue >>= (8 - rbits) 41 | randomdata = struct.pack("B", randomvalue) + randomdata 42 | 43 | return randomdata 44 | 45 | 46 | def read_random_int(nbits: int) -> int: 47 | """Reads a random integer of approximately nbits bits. 48 | """ 49 | 50 | randomdata = read_random_bits(nbits) 51 | value = transform.bytes2int(randomdata) 52 | 53 | # Ensure that the number is large enough to just fill out the required 54 | # number of bits. 55 | value |= 1 << (nbits - 1) 56 | 57 | return value 58 | 59 | 60 | def read_random_odd_int(nbits: int) -> int: 61 | """Reads a random odd integer of approximately nbits bits. 62 | 63 | >>> read_random_odd_int(512) & 1 64 | 1 65 | """ 66 | 67 | value = read_random_int(nbits) 68 | 69 | # Make sure it's odd 70 | return value | 1 71 | 72 | 73 | def randint(maxvalue: int) -> int: 74 | """Returns a random integer x with 1 <= x <= maxvalue 75 | 76 | May take a very long time in specific situations. If maxvalue needs N bits 77 | to store, the closer maxvalue is to (2 ** N) - 1, the faster this function 78 | is. 79 | """ 80 | 81 | bit_size = common.bit_size(maxvalue) 82 | 83 | tries = 0 84 | while True: 85 | value = read_random_int(bit_size) 86 | if value <= maxvalue: 87 | break 88 | 89 | if tries % 10 == 0 and tries: 90 | # After a lot of tries to get the right number of bits but still 91 | # smaller than maxvalue, decrease the number of bits by 1. That'll 92 | # dramatically increase the chances to get a large enough number. 93 | bit_size -= 1 94 | tries += 1 95 | 96 | return value 97 | -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | export LANG="zh_CN.UTF-8" 5 | 6 | echo "Git 拉取最新代码,并安装更新依赖..." 7 | git -C /dailycheckin pull 8 | pip install -r /dailycheckin/requirements.txt 9 | 10 | defaultListFile="/dailycheckin/docker/default_list.sh" 11 | 12 | customListFile="/dailycheckin/docker/$CUSTOM_LIST_FILE" 13 | mergedListFile="/dailycheckin/docker/merged_list_file.sh" 14 | 15 | if type ts >/dev/null 2>&1; then 16 | echo 'moreutils tools installed, default task append |ts output' 17 | echo '系统已安装 moreutils 工具包,默认定时任务增加|ts 输出' 18 | ##复制一个新文件来追加|ts,防止git pull的时候冲突 19 | cp $defaultListFile /dailycheckin/docker/crontab_list.sh 20 | defaultListFile="/dailycheckin/docker/crontab_list.sh" 21 | 22 | sed -i 's/>>/|ts >>/g' $defaultListFile 23 | fi 24 | 25 | if [ $CUSTOM_LIST_FILE ]; then 26 | echo "You have configured a custom list file: $CUSTOM_LIST_FILE, custom list merge type: $CUSTOM_LIST_MERGE_TYPE..." 27 | echo "您配置了自定义任务文件:$CUSTOM_LIST_FILE,自定义任务类型为:$CUSTOM_LIST_MERGE_TYPE..." 28 | if [ -f "$customListFile" ]; then 29 | if [ $CUSTOM_LIST_MERGE_TYPE == "append" ]; then 30 | echo "merge default list file: $DEFAULT_LIST_FILE and custom list file: $CUSTOM_LIST_FILE" 31 | echo "合并默认定时任务文件:$DEFAULT_LIST_FILE 和 自定义定时任务文件:$CUSTOM_LIST_FILE" 32 | cat $defaultListFile >$mergedListFile 33 | echo -e "" >>$mergedListFile 34 | cat $customListFile >>$mergedListFile 35 | elif [ $CUSTOM_LIST_MERGE_TYPE == "overwrite" ]; then 36 | cat $customListFile >$mergedListFile 37 | echo "merge custom list file: $CUSTOM_LIST_FILE..." 38 | echo "合并自定义任务文件:$CUSTOM_LIST_FILE" 39 | touch "$customListFile" 40 | else 41 | echo "配置配置了错误的自定义定时任务类型:$CUSTOM_LIST_MERGE_TYPE,自定义任务类型为只能为append或者overwrite..." 42 | cat $defaultListFile >$mergedListFile 43 | fi 44 | else 45 | echo "Not found custom list file: $CUSTOM_LIST_FILE ,use default list file: $DEFAULT_LIST_FILE" 46 | echo "自定义任务文件:$CUSTOM_LIST_FILE 未找到,使用默认配置$DEFAULT_LIST_FILE..." 47 | cat $defaultListFile >$mergedListFile 48 | fi 49 | else 50 | echo "The currently used is the default crontab task file: $DEFAULT_LIST_FILE ..." 51 | echo "当前使用的为默认定时任务文件 $DEFAULT_LIST_FILE ..." 52 | cat $defaultListFile >$mergedListFile 53 | fi 54 | 55 | # 判断最后要加载的定时任务是否包含默认定时任务,不包含的话就加进去 56 | if [ $(grep -c "default_task.sh" $mergedListFile) -eq '0' ]; then 57 | echo "Merged crontab task file,the required default task is not included, append default task..." 58 | echo "合并后的定时任务文件,未包含必须的默认定时任务,增加默认定时任务..." 59 | echo -e >>$mergedListFile 60 | echo "0 */12 * * * sh /dailycheckin/docker/default_task.sh >> /dailycheckin/logs/default_task.log 2>&1" >>$mergedListFile 61 | fi 62 | 63 | echo "Load the latest crontab task file..." 64 | echo "加载最新的定时任务文件..." 65 | crontab $mergedListFile 66 | 67 | echo "Start crontab task main process..." 68 | echo "启动 crondtab 定时任务主进程..." 69 | 70 | if [ $CUSTOM_LIST_FILE ]; then 71 | chmod -R 777 $customListFile 72 | fi 73 | 74 | crond -f -------------------------------------------------------------------------------- /smzdm/smzdm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | import requests 6 | from requests import utils 7 | 8 | 9 | class SmzdmCheckIn: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def sign(session): 15 | try: 16 | current = session.get(url="https://zhiyou.smzdm.com/user/info/jsonp_get_current").json() 17 | if current["checkin"]["has_checkin"]: 18 | msg = ( 19 | f"用户信息: {current.get('nickname', '')}\n目前积分: {current.get('point', '')}\n" 20 | f"经验值: {current.get('exp', '')}\n金币: {current.get('gold', '')}\n" 21 | f"碎银子: {current.get('silver', '')}\n威望: {current.get('prestige', '')}\n" 22 | f"等级: {current.get('level', '')}\n" 23 | f"已经签到: {current.get('checkin', {}).get('daily_checkin_num', '')} 天" 24 | ) 25 | else: 26 | response = session.get(url="https://zhiyou.smzdm.com/user/checkin/jsonp_checkin").json().get("data", {}) 27 | msg = ( 28 | f"用户信息: {current.get('nickname', '')}\n目前积分: {response.get('point', '')}\n" 29 | f"增加积分: {response.get('add_point', '')}\n经验值: {response.get('exp', '')}\n" 30 | f"金币: {response.get('gold', '')}\n威望: {response.get('prestige', '')}\n" 31 | f"等级: {response.get('rank', '')}\n" 32 | f"已经签到: {response.get('checkin_num', {})} 天" 33 | ) 34 | except Exception as e: 35 | msg = f"签到状态: 签到失败\n错误信息: {e}" 36 | return msg 37 | 38 | def main(self): 39 | smzdm_cookie = { 40 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("smzdm_cookie").split("; ") 41 | } 42 | session = requests.session() 43 | requests.utils.add_dict_to_cookiejar(session.cookies, smzdm_cookie) 44 | session.headers.update( 45 | { 46 | "Accept": "*/*", 47 | "Accept-Encoding": "gzip, deflate, br", 48 | "Accept-Language": "zh-CN,zh;q=0.9", 49 | "Connection": "keep-alive", 50 | "Host": "zhiyou.smzdm.com", 51 | "Referer": "https://www.smzdm.com/", 52 | "Sec-Fetch-Dest": "script", 53 | "Sec-Fetch-Mode": "no-cors", 54 | "Sec-Fetch-Site": "same-site", 55 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", 56 | } 57 | ) 58 | sign_msg = self.sign(session=session) 59 | msg = f"{sign_msg}" 60 | return msg 61 | 62 | 63 | if __name__ == "__main__": 64 | with open( 65 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 66 | ) as f: 67 | datas = json.loads(f.read()) 68 | _check_item = datas.get("SMZDM_COOKIE_LIST", [])[0] 69 | print(SmzdmCheckIn(check_item=_check_item).main()) 70 | -------------------------------------------------------------------------------- /pyasn1/codec/der/decoder.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1.codec.cer import decoder 8 | from pyasn1.type import univ 9 | 10 | __all__ = ['decode'] 11 | 12 | 13 | class BitStringDecoder(decoder.BitStringDecoder): 14 | supportConstructedForm = False 15 | 16 | 17 | class OctetStringDecoder(decoder.OctetStringDecoder): 18 | supportConstructedForm = False 19 | 20 | # TODO: prohibit non-canonical encoding 21 | RealDecoder = decoder.RealDecoder 22 | 23 | tagMap = decoder.tagMap.copy() 24 | tagMap.update( 25 | {univ.BitString.tagSet: BitStringDecoder(), 26 | univ.OctetString.tagSet: OctetStringDecoder(), 27 | univ.Real.tagSet: RealDecoder()} 28 | ) 29 | 30 | typeMap = decoder.typeMap.copy() 31 | 32 | # Put in non-ambiguous types for faster codec lookup 33 | for typeDecoder in tagMap.values(): 34 | if typeDecoder.protoComponent is not None: 35 | typeId = typeDecoder.protoComponent.__class__.typeId 36 | if typeId is not None and typeId not in typeMap: 37 | typeMap[typeId] = typeDecoder 38 | 39 | 40 | class Decoder(decoder.Decoder): 41 | supportIndefLength = False 42 | 43 | 44 | #: Turns DER octet stream into an ASN.1 object. 45 | #: 46 | #: Takes DER octet-stream and decode it into an ASN.1 object 47 | #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which 48 | #: may be a scalar or an arbitrary nested structure. 49 | #: 50 | #: Parameters 51 | #: ---------- 52 | #: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) 53 | #: DER octet-stream 54 | #: 55 | #: Keyword Args 56 | #: ------------ 57 | #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative 58 | #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure 59 | #: being decoded, *asn1Spec* may or may not be required. Most common reason for 60 | #: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. 61 | #: 62 | #: Returns 63 | #: ------- 64 | #: : :py:class:`tuple` 65 | #: A tuple of pyasn1 object recovered from DER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 66 | #: and the unprocessed trailing portion of the *substrate* (may be empty) 67 | #: 68 | #: Raises 69 | #: ------ 70 | #: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError 71 | #: On decoding errors 72 | #: 73 | #: Examples 74 | #: -------- 75 | #: Decode DER serialisation without ASN.1 schema 76 | #: 77 | #: .. code-block:: pycon 78 | #: 79 | #: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03') 80 | #: >>> str(s) 81 | #: SequenceOf: 82 | #: 1 2 3 83 | #: 84 | #: Decode DER serialisation with ASN.1 schema 85 | #: 86 | #: .. code-block:: pycon 87 | #: 88 | #: >>> seq = SequenceOf(componentType=Integer()) 89 | #: >>> s, _ = decode(b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03', asn1Spec=seq) 90 | #: >>> str(s) 91 | #: SequenceOf: 92 | #: 1 2 3 93 | #: 94 | decode = Decoder(tagMap, typeMap) 95 | -------------------------------------------------------------------------------- /rsa/util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Utility functions.""" 16 | 17 | import sys 18 | from optparse import OptionParser 19 | 20 | import rsa.key 21 | 22 | 23 | def private_to_public() -> None: 24 | """Reads a private key and outputs the corresponding public key.""" 25 | 26 | # Parse the CLI options 27 | parser = OptionParser(usage='usage: %prog [options]', 28 | description='Reads a private key and outputs the ' 29 | 'corresponding public key. Both private and public keys use ' 30 | 'the format described in PKCS#1 v1.5') 31 | 32 | parser.add_option('-i', '--input', dest='infilename', type='string', 33 | help='Input filename. Reads from stdin if not specified') 34 | parser.add_option('-o', '--output', dest='outfilename', type='string', 35 | help='Output filename. Writes to stdout of not specified') 36 | 37 | parser.add_option('--inform', dest='inform', 38 | help='key format of input - default PEM', 39 | choices=('PEM', 'DER'), default='PEM') 40 | 41 | parser.add_option('--outform', dest='outform', 42 | help='key format of output - default PEM', 43 | choices=('PEM', 'DER'), default='PEM') 44 | 45 | (cli, cli_args) = parser.parse_args(sys.argv) 46 | 47 | # Read the input data 48 | if cli.infilename: 49 | print('Reading private key from %s in %s format' % 50 | (cli.infilename, cli.inform), file=sys.stderr) 51 | with open(cli.infilename, 'rb') as infile: 52 | in_data = infile.read() 53 | else: 54 | print('Reading private key from stdin in %s format' % cli.inform, 55 | file=sys.stderr) 56 | in_data = sys.stdin.read().encode('ascii') 57 | 58 | assert type(in_data) == bytes, type(in_data) 59 | 60 | # Take the public fields and create a public key 61 | priv_key = rsa.key.PrivateKey.load_pkcs1(in_data, cli.inform) 62 | pub_key = rsa.key.PublicKey(priv_key.n, priv_key.e) 63 | 64 | # Save to the output file 65 | out_data = pub_key.save_pkcs1(cli.outform) 66 | 67 | if cli.outfilename: 68 | print('Writing public key to %s in %s format' % 69 | (cli.outfilename, cli.outform), file=sys.stderr) 70 | with open(cli.outfilename, 'wb') as outfile: 71 | outfile.write(out_data) 72 | else: 73 | print('Writing public key to stdout in %s format' % cli.outform, 74 | file=sys.stderr) 75 | sys.stdout.write(out_data.decode('ascii')) 76 | -------------------------------------------------------------------------------- /v2ex/v2ex.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | import urllib3 8 | from requests import utils 9 | 10 | urllib3.disable_warnings() 11 | 12 | 13 | class V2exCheckIn: 14 | def __init__(self, check_item): 15 | self.check_item = check_item 16 | 17 | @staticmethod 18 | def sign(session): 19 | msg = "" 20 | response = session.get(url="https://www.v2ex.com/mission/daily", verify=False) 21 | pattern = ( 22 | r"" 24 | ) 25 | urls = re.findall(pattern=pattern, string=response.text) 26 | url = urls[0] if urls else None 27 | if url is None: 28 | return "cookie 可能过期" 29 | elif url != "/balance": 30 | headers = {"Referer": "https://www.v2ex.com/mission/daily"} 31 | data = {"once": url.split("=")[-1]} 32 | _ = session.get(url="https://www.v2ex.com" + url, verify=False, headers=headers, params=data) 33 | response = session.get(url="https://www.v2ex.com/balance", verify=False) 34 | total = re.findall( 35 | pattern=r"(\d+\.\d+)", string=response.text 36 | ) 37 | total = total[0] if total else "签到失败" 38 | today = re.findall(pattern=r'(.*?)', string=response.text) 39 | today = today[0] if today else "签到失败" 40 | username = re.findall(pattern=r"(.*?)", string=response.text) 41 | username = username[0] if username else "用户名获取失败" 42 | msg += f"帐号信息: {username}\n今日签到: {today}\n帐号余额: {total}" 43 | response = session.get(url="https://www.v2ex.com/mission/daily", verify=False) 44 | data = re.findall(pattern=r"
(.*?)天
", string=response.text) 45 | data = data[0] + "天" if data else "获取连续签到天数失败" 46 | msg += f"\n签到天数: {data}" 47 | msg = msg.strip() 48 | return msg 49 | 50 | def main(self): 51 | v2ex_cookie = { 52 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("v2ex_cookie").split("; ") 53 | } 54 | session = requests.session() 55 | requests.utils.add_dict_to_cookiejar(session.cookies, v2ex_cookie) 56 | session.headers.update( 57 | { 58 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66", 59 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 60 | "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", 61 | } 62 | ) 63 | msg = self.sign(session=session) 64 | return msg 65 | 66 | 67 | if __name__ == "__main__": 68 | with open( 69 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 70 | ) as f: 71 | datas = json.loads(f.read()) 72 | _check_item = datas.get("V2EX_COOKIE_LIST", [])[0] 73 | print(V2exCheckIn(check_item=_check_item).main()) 74 | -------------------------------------------------------------------------------- /pyasn1/type/opentype.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | 8 | __all__ = ['OpenType'] 9 | 10 | 11 | class OpenType(object): 12 | """Create ASN.1 type map indexed by a value 13 | 14 | The *OpenType* object models an untyped field of a constructed ASN.1 15 | type. In ASN.1 syntax it is usually represented by the 16 | `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, 17 | `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically 18 | used together with :class:`~pyasn1.type.univ.Any` object. 19 | 20 | OpenType objects duck-type a read-only Python :class:`dict` objects, 21 | however the passed `typeMap` is not copied, but stored by reference. 22 | That means the user can manipulate `typeMap` at run time having this 23 | reflected on *OpenType* object behavior. 24 | 25 | The |OpenType| class models an untyped field of a constructed ASN.1 26 | type. In ASN.1 syntax it is usually represented by the 27 | `ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`, 28 | `SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically 29 | used with :class:`~pyasn1.type.univ.Any` type. 30 | 31 | Parameters 32 | ---------- 33 | name: :py:class:`str` 34 | Field name 35 | 36 | typeMap: :py:class:`dict` 37 | A map of value->ASN.1 type. It's stored by reference and can be 38 | mutated later to register new mappings. 39 | 40 | Examples 41 | -------- 42 | 43 | For untyped scalars: 44 | 45 | .. code-block:: python 46 | 47 | openType = OpenType( 48 | 'id', {1: Integer(), 49 | 2: OctetString()} 50 | ) 51 | Sequence( 52 | componentType=NamedTypes( 53 | NamedType('id', Integer()), 54 | NamedType('blob', Any(), openType=openType) 55 | ) 56 | ) 57 | 58 | For untyped `SET OF` or `SEQUENCE OF` vectors: 59 | 60 | .. code-block:: python 61 | 62 | openType = OpenType( 63 | 'id', {1: Integer(), 64 | 2: OctetString()} 65 | ) 66 | Sequence( 67 | componentType=NamedTypes( 68 | NamedType('id', Integer()), 69 | NamedType('blob', SetOf(componentType=Any()), 70 | openType=openType) 71 | ) 72 | ) 73 | """ 74 | 75 | def __init__(self, name, typeMap=None): 76 | self.__name = name 77 | if typeMap is None: 78 | self.__typeMap = {} 79 | else: 80 | self.__typeMap = typeMap 81 | 82 | @property 83 | def name(self): 84 | return self.__name 85 | 86 | # Python dict protocol 87 | 88 | def values(self): 89 | return self.__typeMap.values() 90 | 91 | def keys(self): 92 | return self.__typeMap.keys() 93 | 94 | def items(self): 95 | return self.__typeMap.items() 96 | 97 | def __contains__(self, key): 98 | return key in self.__typeMap 99 | 100 | def __getitem__(self, key): 101 | return self.__typeMap[key] 102 | 103 | def __iter__(self): 104 | return iter(self.__typeMap) 105 | -------------------------------------------------------------------------------- /pyasn1/type/tagmap.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1 import error 8 | 9 | __all__ = ['TagMap'] 10 | 11 | 12 | class TagMap(object): 13 | """Map *TagSet* objects to ASN.1 types 14 | 15 | Create an object mapping *TagSet* object to ASN.1 type. 16 | 17 | *TagMap* objects are immutable and duck-type read-only Python 18 | :class:`dict` objects holding *TagSet* objects as keys and ASN.1 19 | type objects as values. 20 | 21 | Parameters 22 | ---------- 23 | presentTypes: :py:class:`dict` 24 | Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered 25 | as being unconditionally present in the *TagMap*. 26 | 27 | skipTypes: :py:class:`dict` 28 | A collection of :class:`~pyasn1.type.tag.TagSet` objects considered 29 | as absent in the *TagMap* even when *defaultType* is present. 30 | 31 | defaultType: ASN.1 type object 32 | An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present 33 | in *presentTypes* (unless given key is present in *skipTypes*). 34 | """ 35 | def __init__(self, presentTypes=None, skipTypes=None, defaultType=None): 36 | self.__presentTypes = presentTypes or {} 37 | self.__skipTypes = skipTypes or {} 38 | self.__defaultType = defaultType 39 | 40 | def __contains__(self, tagSet): 41 | return (tagSet in self.__presentTypes or 42 | self.__defaultType is not None and tagSet not in self.__skipTypes) 43 | 44 | def __getitem__(self, tagSet): 45 | try: 46 | return self.__presentTypes[tagSet] 47 | except KeyError: 48 | if self.__defaultType is None: 49 | raise KeyError() 50 | elif tagSet in self.__skipTypes: 51 | raise error.PyAsn1Error('Key in negative map') 52 | else: 53 | return self.__defaultType 54 | 55 | def __iter__(self): 56 | return iter(self.__presentTypes) 57 | 58 | def __repr__(self): 59 | representation = '%s object' % self.__class__.__name__ 60 | 61 | if self.__presentTypes: 62 | representation += ', present %s' % repr(self.__presentTypes) 63 | 64 | if self.__skipTypes: 65 | representation += ', skip %s' % repr(self.__skipTypes) 66 | 67 | if self.__defaultType is not None: 68 | representation += ', default %s' % repr(self.__defaultType) 69 | 70 | return '<%s>' % representation 71 | 72 | @property 73 | def presentTypes(self): 74 | """Return *TagSet* to ASN.1 type map present in callee *TagMap*""" 75 | return self.__presentTypes 76 | 77 | @property 78 | def skipTypes(self): 79 | """Return *TagSet* collection unconditionally absent in callee *TagMap*""" 80 | return self.__skipTypes 81 | 82 | @property 83 | def defaultType(self): 84 | """Return default ASN.1 type being returned for any missing *TagSet*""" 85 | return self.__defaultType 86 | 87 | # Backward compatibility 88 | 89 | def getPosMap(self): 90 | return self.presentTypes 91 | 92 | def getNegMap(self): 93 | return self.skipTypes 94 | 95 | def getDef(self): 96 | return self.defaultType 97 | -------------------------------------------------------------------------------- /picacomic/picacomic.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import hashlib 3 | import hmac 4 | import json 5 | import os 6 | import random 7 | import string 8 | import time 9 | 10 | import requests 11 | 12 | 13 | class PicacomicCheckIn: 14 | def __init__(self, check_item): 15 | self.check_item = check_item 16 | 17 | @staticmethod 18 | def generate_headers(path: str, data: dict = None, token: str = None): 19 | api_key = "C69BAF41DA5ABD1FFEDC6D2FEA56B" 20 | api_secret = "~d}$Q7$eIni=V)9\\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn" 21 | headers = { 22 | "api-key": api_key, 23 | "accept": "application/vnd.picacomic.com.v1+json", 24 | "app-channel": "2", 25 | "app-version": "2.2.1.2.3.3", 26 | "app-uuid": "defaultUuid", 27 | "app-platform": "android", 28 | "app-build-version": "44", 29 | "User-Agent": "okhttp/3.8.1", 30 | "image-quality": "original", 31 | } 32 | current_time = str(int(time.time())) 33 | nonce = "".join(random.choices(string.ascii_lowercase + string.digits, k=32)) 34 | raw = path + current_time + nonce + "POST" + api_key 35 | raw = raw.lower() 36 | h = hmac.new(api_secret.encode(), digestmod=hashlib.sha256) 37 | h.update(raw.encode()) 38 | signature = h.hexdigest() 39 | headers["time"] = current_time 40 | headers["nonce"] = nonce 41 | headers["signature"] = signature 42 | if data is not None: 43 | headers["Content-Type"] = "application/json; charset=UTF-8" 44 | if token is not None: 45 | headers["authorization"] = token 46 | return headers 47 | 48 | def sign(self, email, password): 49 | try: 50 | data = {"email": email, "password": password} 51 | sign_headers = self.generate_headers(path="auth/sign-in", data=data) 52 | sign_response = requests.post( 53 | url="https://picaapi.picacomic.com/auth/sign-in", 54 | data=json.dumps({"email": "sitoi", "password": "123456st"}), 55 | headers=sign_headers, 56 | timeout=60, 57 | ).json() 58 | token = sign_response.get("data", {}).get("token") 59 | punch_headers = self.generate_headers(path="users/punch-in", token=token) 60 | response = requests.post( 61 | url="https://picaapi.picacomic.com/users/punch-in", headers=punch_headers, timeout=60 62 | ).json() 63 | if response.get("data", {}).get("res", {}).get("status", {}) == "ok": 64 | msg = "打卡成功" 65 | else: 66 | msg = "重复签到" 67 | except Exception as e: 68 | msg = str(e) 69 | return msg 70 | 71 | def main(self): 72 | picacomic_email = self.check_item.get("picacomic_email") 73 | picacomic_password = self.check_item.get("picacomic_password") 74 | sign_msg = self.sign(email=picacomic_email, password=picacomic_password) 75 | msg = f"帐号信息: {picacomic_email}\n签到状态: {sign_msg}" 76 | return msg 77 | 78 | 79 | if __name__ == "__main__": 80 | with open( 81 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 82 | ) as f: 83 | datas = json.loads(f.read()) 84 | _check_item = datas.get("PICACOMIC_ACCOUNT_LIST", [])[0] 85 | print(PicacomicCheckIn(check_item=_check_item).main()) 86 | -------------------------------------------------------------------------------- /pyasn1/compat/integer.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | import sys 8 | 9 | try: 10 | import platform 11 | 12 | implementation = platform.python_implementation() 13 | 14 | except (ImportError, AttributeError): 15 | implementation = 'CPython' 16 | 17 | from pyasn1.compat.octets import oct2int, null, ensureString 18 | 19 | if sys.version_info[0:2] < (3, 2) or implementation != 'CPython': 20 | from binascii import a2b_hex, b2a_hex 21 | 22 | if sys.version_info[0] > 2: 23 | long = int 24 | 25 | def from_bytes(octets, signed=False): 26 | if not octets: 27 | return 0 28 | 29 | value = long(b2a_hex(ensureString(octets)), 16) 30 | 31 | if signed and oct2int(octets[0]) & 0x80: 32 | return value - (1 << len(octets) * 8) 33 | 34 | return value 35 | 36 | def to_bytes(value, signed=False, length=0): 37 | if value < 0: 38 | if signed: 39 | bits = bitLength(value) 40 | 41 | # two's complement form 42 | maxValue = 1 << bits 43 | valueToEncode = (value + maxValue) % maxValue 44 | 45 | else: 46 | raise OverflowError('can\'t convert negative int to unsigned') 47 | elif value == 0 and length == 0: 48 | return null 49 | else: 50 | bits = 0 51 | valueToEncode = value 52 | 53 | hexValue = hex(valueToEncode)[2:] 54 | if hexValue.endswith('L'): 55 | hexValue = hexValue[:-1] 56 | 57 | if len(hexValue) & 1: 58 | hexValue = '0' + hexValue 59 | 60 | # padding may be needed for two's complement encoding 61 | if value != valueToEncode or length: 62 | hexLength = len(hexValue) * 4 63 | 64 | padLength = max(length, bits) 65 | 66 | if padLength > hexLength: 67 | hexValue = '00' * ((padLength - hexLength - 1) // 8 + 1) + hexValue 68 | elif length and hexLength - length > 7: 69 | raise OverflowError('int too big to convert') 70 | 71 | firstOctet = int(hexValue[:2], 16) 72 | 73 | if signed: 74 | if firstOctet & 0x80: 75 | if value >= 0: 76 | hexValue = '00' + hexValue 77 | elif value < 0: 78 | hexValue = 'ff' + hexValue 79 | 80 | octets_value = a2b_hex(hexValue) 81 | 82 | return octets_value 83 | 84 | def bitLength(number): 85 | # bits in unsigned number 86 | hexValue = hex(abs(number)) 87 | bits = len(hexValue) - 2 88 | if hexValue.endswith('L'): 89 | bits -= 1 90 | if bits & 1: 91 | bits += 1 92 | bits *= 4 93 | # TODO: strip lhs zeros 94 | return bits 95 | 96 | else: 97 | 98 | def from_bytes(octets, signed=False): 99 | return int.from_bytes(bytes(octets), 'big', signed=signed) 100 | 101 | def to_bytes(value, signed=False, length=0): 102 | length = max(value.bit_length(), length) 103 | 104 | if signed and length % 8 == 0: 105 | length += 1 106 | 107 | return value.to_bytes(length // 8 + (length % 8 and 1 or 0), 'big', signed=signed) 108 | 109 | def bitLength(number): 110 | return int(number).bit_length() 111 | -------------------------------------------------------------------------------- /pyasn1/codec/der/encoder.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1 import error 8 | from pyasn1.codec.cer import encoder 9 | from pyasn1.type import univ 10 | 11 | __all__ = ['encode'] 12 | 13 | 14 | class SetEncoder(encoder.SetEncoder): 15 | @staticmethod 16 | def _componentSortKey(componentAndType): 17 | """Sort SET components by tag 18 | 19 | Sort depending on the actual Choice value (dynamic sort) 20 | """ 21 | component, asn1Spec = componentAndType 22 | 23 | if asn1Spec is None: 24 | compType = component 25 | else: 26 | compType = asn1Spec 27 | 28 | if compType.typeId == univ.Choice.typeId and not compType.tagSet: 29 | if asn1Spec is None: 30 | return component.getComponent().tagSet 31 | else: 32 | # TODO: move out of sorting key function 33 | names = [namedType.name for namedType in asn1Spec.componentType.namedTypes 34 | if namedType.name in component] 35 | if len(names) != 1: 36 | raise error.PyAsn1Error( 37 | '%s components for Choice at %r' % (len(names) and 'Multiple ' or 'None ', component)) 38 | 39 | # TODO: support nested CHOICE ordering 40 | return asn1Spec[names[0]].tagSet 41 | 42 | else: 43 | return compType.tagSet 44 | 45 | tagMap = encoder.tagMap.copy() 46 | tagMap.update({ 47 | # Set & SetOf have same tags 48 | univ.Set.tagSet: SetEncoder() 49 | }) 50 | 51 | typeMap = encoder.typeMap.copy() 52 | typeMap.update({ 53 | # Set & SetOf have same tags 54 | univ.Set.typeId: SetEncoder() 55 | }) 56 | 57 | 58 | class Encoder(encoder.Encoder): 59 | fixedDefLengthMode = True 60 | fixedChunkSize = 0 61 | 62 | #: Turns ASN.1 object into DER octet stream. 63 | #: 64 | #: Takes any ASN.1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 65 | #: walks all its components recursively and produces a DER octet stream. 66 | #: 67 | #: Parameters 68 | #: ---------- 69 | #: value: either a Python or pyasn1 object (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 70 | #: A Python or pyasn1 object to encode. If Python object is given, `asnSpec` 71 | #: parameter is required to guide the encoding process. 72 | #: 73 | #: Keyword Args 74 | #: ------------ 75 | #: asn1Spec: 76 | #: Optional ASN.1 schema or value object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative 77 | #: 78 | #: Returns 79 | #: ------- 80 | #: : :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) 81 | #: Given ASN.1 object encoded into BER octet-stream 82 | #: 83 | #: Raises 84 | #: ------ 85 | #: ~pyasn1.error.PyAsn1Error 86 | #: On encoding errors 87 | #: 88 | #: Examples 89 | #: -------- 90 | #: Encode Python value into DER with ASN.1 schema 91 | #: 92 | #: .. code-block:: pycon 93 | #: 94 | #: >>> seq = SequenceOf(componentType=Integer()) 95 | #: >>> encode([1, 2, 3], asn1Spec=seq) 96 | #: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' 97 | #: 98 | #: Encode ASN.1 value object into DER 99 | #: 100 | #: .. code-block:: pycon 101 | #: 102 | #: >>> seq = SequenceOf(componentType=Integer()) 103 | #: >>> seq.extend([1, 2, 3]) 104 | #: >>> encode(seq) 105 | #: b'0\t\x02\x01\x01\x02\x01\x02\x02\x01\x03' 106 | #: 107 | encode = Encoder(tagMap, typeMap) 108 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: 每日签到合集 2 | 3 | on: 4 | schedule: 5 | - cron: '10 16 * * * ' 6 | watch: 7 | types: [ started ] 8 | workflow_dispatch: 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: 'Set up Python' 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: 3.7 20 | 21 | - name: 'Install requirements' 22 | run: pip install -r ./requirements.txt 23 | 24 | - name: '运行【每日签到合集】' 25 | run: python3 index.py 26 | env: 27 | IS_GITHUB_ACTION: true 28 | CONFIG_JSON: ${{ secrets.CONFIG_JSON }} 29 | DINGTALK_SECRET: ${{ secrets.DINGTALK_SECRET }} 30 | DINGTALK_ACCESS_TOKEN: ${{secrets.DINGTALK_ACCESS_TOKEN}} 31 | SCKEY: ${{secrets.SCKEY}} 32 | SENDKEY: ${{secrets.SENDKEY}} 33 | BARK_URL: ${{secrets.BARK_URL}} 34 | QMSG_KEY: ${{secrets.QMSG_KEY}} 35 | QMSG_TYPE: ${{secrets.QMSG_TYPE}} 36 | TG_BOT_TOKEN: ${{secrets.TG_BOT_TOKEN}} 37 | TG_USER_ID: ${{secrets.TG_USER_ID}} 38 | COOLPUSHSKEY: ${{secrets.COOLPUSHSKEY}} 39 | COOLPUSHQQ: ${{secrets.COOLPUSHQQ}} 40 | COOLPUSHWX: ${{secrets.COOLPUSHWX}} 41 | COOLPUSHEMAIL: ${{secrets.COOLPUSHEMAIL}} 42 | QYWX_KEY: ${{secrets.QYWX_KEY}} 43 | QYWX_CORPID: ${{secrets.QYWX_CORPID}} 44 | QYWX_AGENTID: ${{secrets.QYWX_AGENTID}} 45 | QYWX_CORPSECRET: ${{secrets.QYWX_CORPSECRET}} 46 | QYWX_TOUSER: ${{secrets.QYWX_TOUSER}} 47 | PUSHPLUS_TOKEN: ${{secrets.PUSHPLUS_TOKEN}} 48 | PUSHPLUS_TOPIC: ${{secrets.PUSHPLUS_TOPIC}} 49 | CITY_NAME_LIST: ${{secrets.CITY_NAME_LIST}} 50 | MOTTO: ${{secrets.MOTTO}} 51 | IQIYI_COOKIE_LIST: ${{secrets.IQIYI_COOKIE_LIST}} 52 | VQQ_COOKIE_LIST: ${{secrets.VQQ_COOKIE_LIST}} 53 | YOUDAO_COOKIE_LIST: ${{secrets.YOUDAO_COOKIE_LIST}} 54 | KGQQ_COOKIE_LIST: ${{secrets.KGQQ_COOKIE_LIST}} 55 | MUSIC163_ACCOUNT_LIST: ${{secrets.MUSIC163_ACCOUNT_LIST}} 56 | ONEPLUSBBS_COOKIE_LIST: ${{secrets.ONEPLUSBBS_COOKIE_LIST}} 57 | FMAPP_ACCOUNT_LIST: ${{secrets.FMAPP_ACCOUNT_LIST}} 58 | BAIDU_URL_SUBMIT_LIST: ${{secrets.BAIDU_URL_SUBMIT_LIST}} 59 | TIEBA_COOKIE_LIST: ${{secrets.TIEBA_COOKIE_LIST}} 60 | BILIBILI_COOKIE_LIST: ${{secrets.BILIBILI_COOKIE_LIST}} 61 | LIANTONG_ACCOUNT_LIST: ${{secrets.LIANTONG_ACCOUNT_LIST}} 62 | V2EX_COOKIE_LIST: ${{secrets.V2EX_COOKIE_LIST}} 63 | WWW2NZZ_COOKIE_LIST: ${{secrets.WWW2NZZ_COOKIE_LIST}} 64 | SMZDM_COOKIE_LIST: ${{secrets.SMZDM_COOKIE_LIST}} 65 | MIMOTION_ACCOUNT_LIST: ${{secrets.MIMOTION_ACCOUNT_LIST}} 66 | ACFUN_ACCOUNT_LIST: ${{secrets.ACFUN_ACCOUNT_LIST}} 67 | CLOUD189_ACCOUNT_LIST: ${{secrets.CLOUD189_ACCOUNT_LIST}} 68 | WPS_COOKIE_LIST: ${{secrets.WPS_COOKIE_LIST}} 69 | POJIE_COOKIE_LIST: ${{secrets.POJIE_COOKIE_LIST}} 70 | MGTV_PARAMS_LIST: ${{secrets.MGTV_PARAMS_LIST}} 71 | PICACOMIC_ACCOUNT_LIST: ${{secrets.PICACOMIC_ACCOUNT_LIST}} 72 | MEIZU_COOKIE_LIST: ${{secrets.MEIZU_COOKIE_LIST}} 73 | ZHIYOO_COOKIE_LIST: ${{secrets.ZHIYOO_COOKIE_LIST}} 74 | WEIBO_COOKIE_LIST: ${{secrets.WEIBO_COOKIE_LIST}} 75 | DUOKAN_COOKIE_LIST: ${{secrets.DUOKAN_COOKIE_LIST}} 76 | CSDN_COOKIE_LIST: ${{secrets.CSDN_COOKIE_LIST}} 77 | WZYD_DATA_LIST: ${{secrets.WZYD_DATA_LIST}} 78 | WOMAIL_URL_LIST: ${{secrets.WOMAIL_URL_LIST}} 79 | -------------------------------------------------------------------------------- /fmapp/fmapp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | import requests 6 | 7 | 8 | class FMAPPCheckIn: 9 | def __init__(self, check_item): 10 | self.check_item = check_item 11 | 12 | @staticmethod 13 | def sign(headers): 14 | try: 15 | url = "https://fmapp.chinafamilymart.com.cn/api/app/market/member/signin/sign" 16 | response = requests.post(url=url, headers=headers).json() 17 | code = response.get("code") 18 | if code == "200": 19 | data = response.get("data", {}) 20 | msg = ( 21 | f"在坚持{data.get('nextDay')}天即可获得{data.get('nextNumber')}个发米粒\n" 22 | f"签到{data.get('lastDay')}天可获得{data.get('lastNumber')}个发米粒" 23 | ) 24 | else: 25 | msg = response.get("message") 26 | except Exception as e: 27 | print("错误信息", str(e)) 28 | msg = "未知错误,检查日志" 29 | return msg 30 | 31 | @staticmethod 32 | def user_info(headers): 33 | try: 34 | url = "https://fmapp.chinafamilymart.com.cn/api/app/member/info" 35 | response = requests.post(url=url, headers=headers).json() 36 | code = response.get("code") 37 | if code == "200": 38 | data = response.get("data", {}) 39 | msg = data.get("nickName") 40 | else: 41 | msg = response.get("message") 42 | except Exception as e: 43 | print("错误信息", str(e)) 44 | msg = "未知错误,检查日志" 45 | return msg 46 | 47 | @staticmethod 48 | def mili_count(headers): 49 | try: 50 | url = "https://fmapp.chinafamilymart.com.cn/api/app/member/v1/mili/service/detail" 51 | response = requests.post(url=url, headers=headers, data=json.dumps({"pageSize": 10, "pageNo": 1})).json() 52 | code = response.get("code") 53 | if code == "200": 54 | data = response.get("data", {}) 55 | msg = data.get("miliNum") 56 | else: 57 | msg = response.get("message") 58 | except Exception as e: 59 | print("错误信息", str(e)) 60 | msg = "未知错误,检查日志" 61 | return msg 62 | 63 | def main(self): 64 | fmapp_token = self.check_item.get("fmapp_token") 65 | fmapp_cookie = self.check_item.get("fmapp_cookie") 66 | fmapp_blackbox = self.check_item.get("fmapp_blackbox") 67 | fmapp_device_id = self.check_item.get("fmapp_device_id") 68 | headers = { 69 | "Accept": "*/*", 70 | "Accept-Language": "zh-Hans;q=1.0", 71 | "Accept-Encoding": "br;q=1.0, gzip;q=0.9, deflate;q=0.8", 72 | "Host": "fmapp.chinafamilymart.com.cn", 73 | "Content-Type": "application/json", 74 | "loginChannel": "app", 75 | "token": fmapp_token, 76 | "fmVersion": "2.2.3", 77 | "deviceId": fmapp_device_id, 78 | "User-Agent": "Fa", 79 | "os": "ios", 80 | "cookie": fmapp_cookie, 81 | "blackBox": fmapp_blackbox, 82 | } 83 | sign_msg = self.sign(headers=headers) 84 | name_msg = self.user_info(headers=headers) 85 | mili_msg = self.mili_count(headers=headers) 86 | msg = f"帐号信息: {name_msg}\n签到状态: {sign_msg}\n米粒数量: {mili_msg}" 87 | return msg 88 | 89 | 90 | if __name__ == "__main__": 91 | with open( 92 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 93 | ) as f: 94 | datas = json.loads(f.read()) 95 | _check_item = datas.get("FMAPP_ACCOUNT_LIST", [])[0] 96 | print(FMAPPCheckIn(check_item=_check_item).main()) 97 | -------------------------------------------------------------------------------- /rsa/pkcs1_v2.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Functions for PKCS#1 version 2 encryption and signing 16 | 17 | This module implements certain functionality from PKCS#1 version 2. Main 18 | documentation is RFC 2437: https://tools.ietf.org/html/rfc2437 19 | """ 20 | 21 | from rsa import ( 22 | common, 23 | pkcs1, 24 | transform, 25 | ) 26 | 27 | 28 | def mgf1(seed: bytes, length: int, hasher: str = 'SHA-1') -> bytes: 29 | """ 30 | MGF1 is a Mask Generation Function based on a hash function. 31 | 32 | A mask generation function takes an octet string of variable length and a 33 | desired output length as input, and outputs an octet string of the desired 34 | length. The plaintext-awareness of RSAES-OAEP relies on the random nature of 35 | the output of the mask generation function, which in turn relies on the 36 | random nature of the underlying hash. 37 | 38 | :param bytes seed: seed from which mask is generated, an octet string 39 | :param int length: intended length in octets of the mask, at most 2^32(hLen) 40 | :param str hasher: hash function (hLen denotes the length in octets of the hash 41 | function output) 42 | 43 | :return: mask, an octet string of length `length` 44 | :rtype: bytes 45 | 46 | :raise OverflowError: when `length` is too large for the specified `hasher` 47 | :raise ValueError: when specified `hasher` is invalid 48 | """ 49 | 50 | try: 51 | hash_length = pkcs1.HASH_METHODS[hasher]().digest_size 52 | except KeyError: 53 | raise ValueError( 54 | 'Invalid `hasher` specified. Please select one of: {hash_list}'.format( 55 | hash_list=', '.join(sorted(pkcs1.HASH_METHODS.keys())) 56 | ) 57 | ) 58 | 59 | # If l > 2^32(hLen), output "mask too long" and stop. 60 | if length > (2**32 * hash_length): 61 | raise OverflowError( 62 | "Desired length should be at most 2**32 times the hasher's output " 63 | "length ({hash_length} for {hasher} function)".format( 64 | hash_length=hash_length, 65 | hasher=hasher, 66 | ) 67 | ) 68 | 69 | # Looping `counter` from 0 to ceil(l / hLen)-1, build `output` based on the 70 | # hashes formed by (`seed` + C), being `C` an octet string of length 4 71 | # generated by converting `counter` with the primitive I2OSP 72 | output = b''.join( 73 | pkcs1.compute_hash( 74 | seed + transform.int2bytes(counter, fill_size=4), 75 | method_name=hasher, 76 | ) 77 | for counter in range(common.ceil_div(length, hash_length) + 1) 78 | ) 79 | 80 | # Output the leading `length` octets of `output` as the octet string mask. 81 | return output[:length] 82 | 83 | 84 | __all__ = [ 85 | 'mgf1', 86 | ] 87 | 88 | if __name__ == '__main__': 89 | print('Running doctests 1000x or until failure') 90 | import doctest 91 | 92 | for count in range(1000): 93 | (failures, tests) = doctest.testmod() 94 | if failures: 95 | break 96 | 97 | if count % 100 == 0 and count: 98 | print('%i times' % count) 99 | 100 | print('Doctests done') 101 | -------------------------------------------------------------------------------- /tieba/tieba.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import hashlib 3 | import json 4 | import os 5 | import re 6 | 7 | import requests 8 | from requests import utils 9 | 10 | 11 | class TiebaCheckIn: 12 | def __init__(self, check_item): 13 | self.check_item = check_item 14 | 15 | @staticmethod 16 | def login_info(session): 17 | return session.get(url="https://zhidao.baidu.com/api/loginInfo").json() 18 | 19 | def valid(self, session): 20 | try: 21 | content = session.get(url="http://tieba.baidu.com/dc/common/tbs") 22 | except Exception as e: 23 | return False, f"登录验证异常,错误信息: {e}" 24 | data = json.loads(content.text) 25 | if data["is_login"] == 0: 26 | return False, "登录失败,cookie 异常" 27 | tbs = data["tbs"] 28 | user_name = self.login_info(session=session)["userName"] 29 | return tbs, user_name 30 | 31 | @staticmethod 32 | def tieba_list_more(session): 33 | content = session.get(url="http://tieba.baidu.com/f/like/mylike?&pn=1", timeout=(5, 20)) 34 | try: 35 | pn = int(re.match(r".*/f/like/mylike\?&pn=(.*?)\">尾页.*", content.text, re.S | re.I).group(1)) 36 | except Exception as e: 37 | pn = 1 38 | next_page = 1 39 | pattern = re.compile(r".*?") 40 | while next_page <= pn: 41 | tbname = pattern.findall(content.text) 42 | for x in tbname: 43 | yield x 44 | next_page += 1 45 | content = session.get(url=f"http://tieba.baidu.com/f/like/mylike?&pn={next_page}", timeout=(5, 20)) 46 | 47 | def get_tieba_list(self, session): 48 | tieba_list = list(self.tieba_list_more(session=session)) 49 | return tieba_list 50 | 51 | @staticmethod 52 | def sign(session, tb_name_list, tbs): 53 | success_count, error_count, exist_count, shield_count = 0, 0, 0, 0 54 | for tb_name in tb_name_list: 55 | md5 = hashlib.md5(f"kw={tb_name}tbs={tbs}tiebaclient!!!".encode("utf-8")).hexdigest() 56 | data = {"kw": tb_name, "tbs": tbs, "sign": md5} 57 | try: 58 | response = session.post(url="http://c.tieba.baidu.com/c/c/forum/sign", data=data).json() 59 | if response["error_code"] == "0": 60 | success_count += 1 61 | elif response["error_code"] == "160002": 62 | exist_count += 1 63 | elif response["error_code"] == "340006": 64 | shield_count += 1 65 | else: 66 | error_count += 1 67 | except Exception as e: 68 | print(f"贴吧 {tb_name} 签到异常,原因{str(e)}") 69 | msg = f"贴吧总数: {len(tb_name_list)}\n签到成功: {success_count}\n已经签到: {exist_count}\n被屏蔽的: {shield_count}\n签到失败: {error_count}" 70 | return msg 71 | 72 | def main(self): 73 | tieba_cookie = { 74 | item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("tieba_cookie").split("; ") 75 | } 76 | session = requests.session() 77 | requests.utils.add_dict_to_cookiejar(session.cookies, tieba_cookie) 78 | session.headers.update({"Referer": "https://www.baidu.com/"}) 79 | tbs, user_name = self.valid(session=session) 80 | if tbs: 81 | tb_name_list = self.get_tieba_list(session=session) 82 | msg = self.sign(session=session, tb_name_list=tb_name_list, tbs=tbs) 83 | msg = f"帐号信息: {user_name}\n{msg}" 84 | else: 85 | msg = f"帐号信息: {user_name}\n签到状态: Cookie 可能过期" 86 | return msg 87 | 88 | 89 | if __name__ == "__main__": 90 | with open( 91 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 92 | ) as f: 93 | datas = json.loads(f.read()) 94 | _check_item = datas.get("TIEBA_COOKIE_LIST", [])[0] 95 | print(TiebaCheckIn(check_item=_check_item).main()) 96 | -------------------------------------------------------------------------------- /weibo/weibo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | from urllib import parse 5 | 6 | import requests 7 | import urllib3 8 | 9 | urllib3.disable_warnings() 10 | 11 | 12 | class WeiBoCheckIn: 13 | def __init__(self, check_item): 14 | self.check_item = check_item 15 | 16 | @staticmethod 17 | def sign(token): 18 | headers = {"User-Agent": "Weibo/52588 (iPhone; iOS 14.5; Scale/3.00)"} 19 | response = requests.get( 20 | url=f"https://api.weibo.cn/2/checkin/add?c=iphone&{token}", headers=headers, verify=False 21 | ) 22 | result = response.json() 23 | if result.get("status") == 10000: 24 | msg = f'连续签到: {result.get("data").get("continuous")}天\n本次收益: {result.get("data").get("desc")}' 25 | elif result.get("errno") == 30000: 26 | msg = f"每日签到: 已签到" 27 | elif result.get("status") == 90005: 28 | msg = f'每日签到: {result.get("msg")}' 29 | else: 30 | msg = f"每日签到: 签到失败" 31 | return msg 32 | 33 | @staticmethod 34 | def card(token): 35 | headers = {"User-Agent": "Weibo/52588 (iPhone; iOS 14.5; Scale/3.00)"} 36 | response = requests.get( 37 | url=f"https://api.weibo.cn/2/!/ug/king_act_home?c=iphone&{token}", headers=headers, verify=False 38 | ) 39 | result = response.json() 40 | if result.get("status") == 10000: 41 | nickname = result.get("data").get("user").get("nickname") 42 | msg = ( 43 | f'用户昵称: {nickname}\n每日打卡: {result.get("data").get("signin").get("title").split("<")[0]}天\n' 44 | f'积分总计: {result.get("data").get("user").get("energy")}' 45 | ) 46 | else: 47 | msg = f"每日打卡: 活动过期或失效" 48 | return msg 49 | 50 | @staticmethod 51 | def pay(token): 52 | headers = { 53 | "Accept-Encoding": "gzip, deflate", 54 | "Connection": "keep-alive", 55 | "Content-Type": "application/x-www-form-urlencoded", 56 | "Host": "pay.sc.weibo.com", 57 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Weibo (iPhone10,1__weibo__11.2.1__iphone__os14.5)", 58 | } 59 | data = token + "&lang=zh_CN&wm=3333_2001" 60 | response = requests.post( 61 | url=f"https://pay.sc.weibo.com/aj/mobile/home/welfare/signin/do", headers=headers, data=data, verify=False 62 | ) 63 | try: 64 | result = response.json() 65 | if result.get("status") == 1: 66 | msg = f'微博钱包: {result.get("score")} 积分' 67 | elif result.get("status") == 2: 68 | msg = f"微博钱包: 已签到" 69 | info_response = requests.post( 70 | url="https://pay.sc.weibo.com/api/client/sdk/app/balance", headers=headers, data=data 71 | ) 72 | info_result = info_response.json() 73 | msg += f"\n当前现金: {info_result.get('data').get('balance')} 元" 74 | else: 75 | msg = f"微博钱包: Cookie失效" 76 | return msg 77 | except Exception as e: 78 | msg = f"微博钱包: Cookie失效" 79 | return msg 80 | 81 | def main(self): 82 | weibo_show_url = self.check_item.get("weibo_show_url") 83 | query_dict = dict(parse.parse_qsl(parse.urlsplit(weibo_show_url).query)) 84 | token = "&".join([f"{key}={value}" for key, value in query_dict.items() if key in ["from", "uid", "s", "gsid"]]) 85 | sign_msg = self.sign(token=token) 86 | card_msg = self.card(token=token) 87 | pay_msg = self.pay(token=token) 88 | msg = f"{sign_msg}\n{card_msg}\n{pay_msg}" 89 | return msg 90 | 91 | 92 | if __name__ == "__main__": 93 | with open( 94 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 95 | ) as f: 96 | datas = json.loads(f.read()) 97 | _check_item = datas.get("WEIBO_COOKIE_LIST", [])[0] 98 | print(WeiBoCheckIn(check_item=_check_item).main()) 99 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
每日签到集合 4 |
基于【腾讯云函数】/【GitHub Actions】/【Docker】的每日签到脚本 5 |
支持多账号使用 6 |

7 | 8 |

9 | Telegram 10 | GitHub stars 11 | GitHub forks 12 | GitHub issues 13 | Docker Pulls 14 | visitor 15 |

16 | 17 | ## 签到列表 18 | 19 | 🟢: 正常运行 🔴: 脚本暂不可用 🔵: 可以执行(需更新) 🟡: 待测试 🟤: 看脸 20 | 21 | |类别|名称|备注|终端|Cookie 时长|状态| 22 | |:---:|:---:|:---|:---:|:---:|:---:| 23 | |签到|[爱奇艺](https://www.iqiyi.com/)|签7天奖1天,14天奖2天,28天奖7天;日常任务4成长值;随机成长值;三次抽奖|WEB|待测试|🟢️| 24 | |签到|[全民K歌](https://kg.qq.com/index-pc.html)|每日签到获取鲜花 每日大约 150 鲜花左右|WEB|待测试|🟢️| 25 | |签到|[腾讯视频](https://v.qq.com/)|每日两次腾讯视频签到获取成长值|WEB|待测试|🟢️| 26 | |签到|[有道云笔记](https://note.youdao.com/web/)|每日签到获取存储空间|WEB|待测试|🟢️| 27 | |签到|[网易云音乐](https://music.163.com/)|每日自动登录签到 + 刷歌 310 首|WEB|永久|🟢️| 28 | |签到|[一加手机社区官方论坛](https://www.oneplusbbs.com/)|论坛每日签到 + 10 次抽奖任务|WEB|待测试|🟢️| 29 | |签到|[百度贴吧](https://tieba.baidu.com/index.html)|贴吧每日签到|WEB|待测试|🟢️| 30 | |签到|[Bilibili](https://www.bilibili.com)|直播签到,漫画签到,每日经验任务,自动投币,银瓜子换硬币等功能|WEB|待测试|🟢️| 31 | |签到|[V2EX](https://www.v2ex.com/)|铜币奖励|WEB|待测试|🟢️| 32 | |签到|[咔叽网单](https://www.2nzz.com/)|论坛金币|WEB|待测试|🟢️| 33 | |签到|[什么值得买](https://www.smzdm.com)|每日签到|WEB|待测试|🟢️| 34 | |签到|[AcFun](https://www.acfun.cn/)|每日签到香蕉|WEB|永久|🟢️| 35 | |签到|[天翼云盘](https://cloud.189.cn/)|每日签到 +2次抽奖获得空间奖励|WEB|永久|🟢️| 36 | |签到|[WPS](https://www.wps.cn/)|每日签到|WEB|待测试|🟢️| 37 | |签到|[吾爱破解](https://www.52pojie.cn/index.php)|2枚吾爱币|WEB|待测试|🟤| 38 | |签到|[哔咔漫画](https://www.picacomic.com)|成长值奖励|WEB|永久|🟤| 39 | |签到|[MEIZU 社区](https://bbs.meizu.cn)|每日签到、可配置抽奖|WEB|待测试|🟢️| 40 | |签到|[智友邦](http://zhizhiyoo.net/)|每日签到获取金币|WEB|待测试|🟢️| 41 | |签到|[CSDN](https://www.csdn.net/)|每日签到、抽奖|WEB|待测试|🟢️| 42 | |签到|联通沃邮箱|每日签到,签到7天得2元话费|公众号|待测试|🟡| 43 | |签到|王者营地|每日签到(仅限 QQ 区)|APP|待测试|🟢| 44 | |签到|微博|每日钱包签到、打卡|APP|待测试|🟢️| 45 | |签到|多看阅读|获取书豆,用于购买书籍|APP|待测试|🟢️| 46 | |签到|芒果 TV|签到获取体验会员|APP|待测试|🟢️| 47 | |签到|联通营业厅|积分+流量奖励|APP|待测试|🟢️| 48 | |签到|Fa 米家|连续签到7天总计获得6粒Fa米粒,每月15号23.59分清空Fa米粒。理论一个月最少获得24粒fa米粒。|APP|待测试|🟢️| 49 | |其他|小米运动|每日小米运动刷步数|APP|永久|🟢️| 50 | |其他|[百度搜索资源平台](https://ziyuan.baidu.com/site/index#/)|提交网站页面供百度收录|WEB|永久|🟢️| 51 | |其他|每日天气预报|获取指定的多个城市天气信息|WEB|永久|🟢️| 52 | |其他|每日一句|从词霸中获取每日一句,带英文|WEB|永久|🟢️| 53 | 54 | ## 支持的通知列表 55 | 56 | - dingtalk(钉钉) 57 | - 企业微信群机器人(企业微信) 58 | - 企业微信应用消息(企业微信) 59 | - telegram(TG) 60 | - Bark(iOS) 61 | - server 酱(微信) 62 | - server 酱 TURBO(微信) 63 | - pushplus(微信) 64 | - Cool Push(QQ,微信,邮箱) 65 | - qmsg 酱(QQ) 66 | 67 | ## 交流群 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |

微信群

扫码进微信交流二群

QQ群

扫码进QQ群

微信号

进群加微信,备注:签到

-------------------------------------------------------------------------------- /meizu/meizu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import time 5 | 6 | import requests 7 | 8 | 9 | class MeizuCheckIn: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def sign(cookie): 15 | headers = { 16 | "authority": "bbs-act.meizu.cn", 17 | "pragma": "no-cache", 18 | "cache-control": "no-cache", 19 | "accept": "application/json, text/javascript, */*; q=0.01", 20 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74", 21 | "origin": "https://bbs.meizu.cn", 22 | "referer": "https://bbs.meizu.cn/", 23 | "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", 24 | "cookie": cookie, 25 | } 26 | params = ( 27 | ("mod", "signin"), 28 | ("action", "sign"), 29 | ) 30 | response = requests.get(url="https://bbs-act.meizu.cn/index.php", headers=headers, params=params).json() 31 | msg = response.get("message") 32 | return msg 33 | 34 | @staticmethod 35 | def draw(cookie, count: int = 0): 36 | headers = { 37 | "authority": "bbs-act.meizu.cn", 38 | "accept": "application/json, text/javascript, */*; q=0.01", 39 | "x-requested-with": "XMLHttpRequest", 40 | "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74", 41 | "content-type": "application/x-www-form-urlencoded", 42 | "origin": "https://bbs-act.meizu.cn", 43 | "referer": "https://bbs-act.meizu.cn/2/index.html", 44 | "accept-language": "zh-CN,zh;q=0.9", 45 | "cookie": cookie, 46 | } 47 | data = {"mod": "index", "action": "draw", "id": "2"} 48 | award_list = [] 49 | success_count = 0 50 | error_count = 0 51 | if count: 52 | for i in range(count): 53 | try: 54 | data = requests.post(url="https://bbs-act.meizu.cn/index.php", headers=headers, data=data).json() 55 | if data["code"] == 200: 56 | one_msg = data.get("data", {}).get("award_name") 57 | award_list.append(one_msg) 58 | success_count += 1 59 | else: 60 | error_count += 1 61 | print(data.get("code"), data.get("message")) 62 | one_msg = "抽奖失败" 63 | except Exception as e: 64 | one_msg = f"抽奖失败: {e}" 65 | error_count += 1 66 | print(f"第{i + 1}次抽奖结果:" + str(one_msg)) 67 | time.sleep(5) 68 | msg = f"成功抽奖 {success_count} 次" 69 | draw_msg = "抽奖状态: " + str(msg) 70 | draw_msg += f"\n抽奖结果: {';'.join(award_list)}" 71 | else: 72 | draw_msg = "抽奖结果: 未开启抽奖" 73 | data = {"mod": "index", "action": "get_user_count", "id": "2"} 74 | user_info = requests.post("https://bbs-act.meizu.cn/index.php", headers=headers, data=data).json() 75 | uid = user_info.get("data", {}).get("uid") 76 | return draw_msg, uid 77 | 78 | def main(self): 79 | meizu_cookie = self.check_item.get("meizu_cookie") 80 | try: 81 | draw_count = int(self.check_item.get("draw_count", 0)) 82 | except Exception as e: 83 | print("初始化抽奖次数失败: 重置为 0 ", str(e)) 84 | draw_count = 0 85 | sign_msg = self.sign(cookie=meizu_cookie) 86 | draw_msg, uid = self.draw(cookie=meizu_cookie, count=draw_count) 87 | msg = f"帐号信息: {uid}\n签到信息: {sign_msg}\n{draw_msg}" 88 | return msg 89 | 90 | 91 | if __name__ == "__main__": 92 | with open( 93 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 94 | ) as f: 95 | datas = json.loads(f.read()) 96 | _check_item = datas.get("MEIZU_COOKIE_LIST", [])[0] 97 | print(MeizuCheckIn(check_item=_check_item).main()) 98 | -------------------------------------------------------------------------------- /pyasn1/codec/cer/decoder.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | from pyasn1 import error 8 | from pyasn1.codec.ber import decoder 9 | from pyasn1.compat.octets import oct2int 10 | from pyasn1.type import univ 11 | 12 | __all__ = ['decode'] 13 | 14 | 15 | class BooleanDecoder(decoder.AbstractSimpleDecoder): 16 | protoComponent = univ.Boolean(0) 17 | 18 | def valueDecoder(self, substrate, asn1Spec, 19 | tagSet=None, length=None, state=None, 20 | decodeFun=None, substrateFun=None, 21 | **options): 22 | head, tail = substrate[:length], substrate[length:] 23 | if not head or length != 1: 24 | raise error.PyAsn1Error('Not single-octet Boolean payload') 25 | byte = oct2int(head[0]) 26 | # CER/DER specifies encoding of TRUE as 0xFF and FALSE as 0x0, while 27 | # BER allows any non-zero value as TRUE; cf. sections 8.2.2. and 11.1 28 | # in https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 29 | if byte == 0xff: 30 | value = 1 31 | elif byte == 0x00: 32 | value = 0 33 | else: 34 | raise error.PyAsn1Error('Unexpected Boolean payload: %s' % byte) 35 | return self._createComponent(asn1Spec, tagSet, value, **options), tail 36 | 37 | # TODO: prohibit non-canonical encoding 38 | BitStringDecoder = decoder.BitStringDecoder 39 | OctetStringDecoder = decoder.OctetStringDecoder 40 | RealDecoder = decoder.RealDecoder 41 | 42 | tagMap = decoder.tagMap.copy() 43 | tagMap.update( 44 | {univ.Boolean.tagSet: BooleanDecoder(), 45 | univ.BitString.tagSet: BitStringDecoder(), 46 | univ.OctetString.tagSet: OctetStringDecoder(), 47 | univ.Real.tagSet: RealDecoder()} 48 | ) 49 | 50 | typeMap = decoder.typeMap.copy() 51 | 52 | # Put in non-ambiguous types for faster codec lookup 53 | for typeDecoder in tagMap.values(): 54 | if typeDecoder.protoComponent is not None: 55 | typeId = typeDecoder.protoComponent.__class__.typeId 56 | if typeId is not None and typeId not in typeMap: 57 | typeMap[typeId] = typeDecoder 58 | 59 | 60 | class Decoder(decoder.Decoder): 61 | pass 62 | 63 | 64 | #: Turns CER octet stream into an ASN.1 object. 65 | #: 66 | #: Takes CER octet-stream and decode it into an ASN.1 object 67 | #: (e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative) which 68 | #: may be a scalar or an arbitrary nested structure. 69 | #: 70 | #: Parameters 71 | #: ---------- 72 | #: substrate: :py:class:`bytes` (Python 3) or :py:class:`str` (Python 2) 73 | #: CER octet-stream 74 | #: 75 | #: Keyword Args 76 | #: ------------ 77 | #: asn1Spec: any pyasn1 type object e.g. :py:class:`~pyasn1.type.base.PyAsn1Item` derivative 78 | #: A pyasn1 type object to act as a template guiding the decoder. Depending on the ASN.1 structure 79 | #: being decoded, *asn1Spec* may or may not be required. Most common reason for 80 | #: it to require is that ASN.1 structure is encoded in *IMPLICIT* tagging mode. 81 | #: 82 | #: Returns 83 | #: ------- 84 | #: : :py:class:`tuple` 85 | #: A tuple of pyasn1 object recovered from CER substrate (:py:class:`~pyasn1.type.base.PyAsn1Item` derivative) 86 | #: and the unprocessed trailing portion of the *substrate* (may be empty) 87 | #: 88 | #: Raises 89 | #: ------ 90 | #: ~pyasn1.error.PyAsn1Error, ~pyasn1.error.SubstrateUnderrunError 91 | #: On decoding errors 92 | #: 93 | #: Examples 94 | #: -------- 95 | #: Decode CER serialisation without ASN.1 schema 96 | #: 97 | #: .. code-block:: pycon 98 | #: 99 | #: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00') 100 | #: >>> str(s) 101 | #: SequenceOf: 102 | #: 1 2 3 103 | #: 104 | #: Decode CER serialisation with ASN.1 schema 105 | #: 106 | #: .. code-block:: pycon 107 | #: 108 | #: >>> seq = SequenceOf(componentType=Integer()) 109 | #: >>> s, _ = decode(b'0\x80\x02\x01\x01\x02\x01\x02\x02\x01\x03\x00\x00', asn1Spec=seq) 110 | #: >>> str(s) 111 | #: SequenceOf: 112 | #: 1 2 3 113 | #: 114 | decode = Decoder(tagMap, decoder.typeMap) 115 | -------------------------------------------------------------------------------- /.github/workflows/deploy_tencent_scf.yml: -------------------------------------------------------------------------------- 1 | name: 部署到腾讯云函数 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | if: github.event.repository.owner.id == github.event.sender.id 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | with: 14 | repository: ${{ github.repository }} 15 | 16 | - name: 'Set up Python' 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: 3.7 20 | 21 | - name: 'Install requirements' 22 | run: pip install -r ./requirements.txt 23 | 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v1 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | 29 | - name: "安装依赖和 serverless 工具" 30 | run: | 31 | npm install 32 | sudo npm install serverless -g 33 | 34 | - name: "将 Secrets 里面配置的变量渲染成 config.json 文件" 35 | run: | 36 | python3.7 config.py 37 | env: #因为直接读取secrets里面的值很多字符不会自动转译,导致写入serverless.yml异常,所以设置到环境变量,在读取环境变量转译过的值 38 | CONFIG_JSON: ${{ secrets.CONFIG_JSON }} 39 | DINGTALK_SECRET: ${{ secrets.DINGTALK_SECRET }} 40 | DINGTALK_ACCESS_TOKEN: ${{secrets.DINGTALK_ACCESS_TOKEN}} 41 | SCKEY: ${{secrets.SCKEY}} 42 | SENDKEY: ${{secrets.SENDKEY}} 43 | BARK_URL: ${{secrets.BARK_URL}} 44 | QMSG_KEY: ${{secrets.QMSG_KEY}} 45 | QMSG_TYPE: ${{secrets.QMSG_TYPE}} 46 | TG_BOT_TOKEN: ${{secrets.TG_BOT_TOKEN}} 47 | TG_USER_ID: ${{secrets.TG_USER_ID}} 48 | COOLPUSHSKEY: ${{secrets.COOLPUSHSKEY}} 49 | COOLPUSHQQ: ${{secrets.COOLPUSHQQ}} 50 | COOLPUSHWX: ${{secrets.COOLPUSHWX}} 51 | COOLPUSHEMAIL: ${{secrets.COOLPUSHEMAIL}} 52 | QYWX_KEY: ${{secrets.QYWX_KEY}} 53 | QYWX_CORPID: ${{secrets.QYWX_CORPID}} 54 | QYWX_AGENTID: ${{secrets.QYWX_AGENTID}} 55 | QYWX_CORPSECRET: ${{secrets.QYWX_CORPSECRET}} 56 | QYWX_TOUSER: ${{secrets.QYWX_TOUSER}} 57 | PUSHPLUS_TOKEN: ${{secrets.PUSHPLUS_TOKEN}} 58 | PUSHPLUS_TOPIC: ${{secrets.PUSHPLUS_TOPIC}} 59 | CITY_NAME_LIST: ${{secrets.CITY_NAME_LIST}} 60 | MOTTO: ${{secrets.MOTTO}} 61 | IQIYI_COOKIE_LIST: ${{secrets.IQIYI_COOKIE_LIST}} 62 | VQQ_COOKIE_LIST: ${{secrets.VQQ_COOKIE_LIST}} 63 | YOUDAO_COOKIE_LIST: ${{secrets.YOUDAO_COOKIE_LIST}} 64 | KGQQ_COOKIE_LIST: ${{secrets.KGQQ_COOKIE_LIST}} 65 | MUSIC163_ACCOUNT_LIST: ${{secrets.MUSIC163_ACCOUNT_LIST}} 66 | ONEPLUSBBS_COOKIE_LIST: ${{secrets.ONEPLUSBBS_COOKIE_LIST}} 67 | FMAPP_ACCOUNT_LIST: ${{secrets.FMAPP_ACCOUNT_LIST}} 68 | BAIDU_URL_SUBMIT_LIST: ${{secrets.BAIDU_URL_SUBMIT_LIST}} 69 | TIEBA_COOKIE_LIST: ${{secrets.TIEBA_COOKIE_LIST}} 70 | BILIBILI_COOKIE_LIST: ${{secrets.BILIBILI_COOKIE_LIST}} 71 | LIANTONG_ACCOUNT_LIST: ${{secrets.LIANTONG_ACCOUNT_LIST}} 72 | V2EX_COOKIE_LIST: ${{secrets.V2EX_COOKIE_LIST}} 73 | WWW2NZZ_COOKIE_LIST: ${{secrets.WWW2NZZ_COOKIE_LIST}} 74 | SMZDM_COOKIE_LIST: ${{secrets.SMZDM_COOKIE_LIST}} 75 | MIMOTION_ACCOUNT_LIST: ${{secrets.MIMOTION_ACCOUNT_LIST}} 76 | ACFUN_ACCOUNT_LIST: ${{secrets.ACFUN_ACCOUNT_LIST}} 77 | CLOUD189_ACCOUNT_LIST: ${{secrets.CLOUD189_ACCOUNT_LIST}} 78 | WPS_COOKIE_LIST: ${{secrets.WPS_COOKIE_LIST}} 79 | POJIE_COOKIE_LIST: ${{secrets.POJIE_COOKIE_LIST}} 80 | MGTV_PARAMS_LIST: ${{secrets.MGTV_PARAMS_LIST}} 81 | PICACOMIC_ACCOUNT_LIST: ${{secrets.PICACOMIC_ACCOUNT_LIST}} 82 | MEIZU_COOKIE_LIST: ${{secrets.MEIZU_COOKIE_LIST}} 83 | ZHIYOO_COOKIE_LIST: ${{secrets.ZHIYOO_COOKIE_LIST}} 84 | WEIBO_COOKIE_LIST: ${{secrets.WEIBO_COOKIE_LIST}} 85 | DUOKAN_COOKIE_LIST: ${{secrets.DUOKAN_COOKIE_LIST}} 86 | CSDN_COOKIE_LIST: ${{secrets.CSDN_COOKIE_LIST}} 87 | WZYD_DATA_LIST: ${{secrets.WZYD_DATA_LIST}} 88 | WOMAIL_URL_LIST: ${{secrets.WOMAIL_URL_LIST}} 89 | 90 | - name: "部署到腾讯云函数" 91 | run: sls deploy --debug 92 | env: 93 | STAGE: dev 94 | SERVERLESS_PLATFORM_VENDOR: tencent 95 | TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }} 96 | TENCENT_SECRET_KEY: ${{ secrets.TENCENT_SECRET_KEY }} 97 | -------------------------------------------------------------------------------- /pyasn1/debug.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | import logging 8 | import sys 9 | 10 | from pyasn1 import __version__ 11 | from pyasn1 import error 12 | from pyasn1.compat.octets import octs2ints 13 | 14 | __all__ = ['Debug', 'setLogger', 'hexdump'] 15 | 16 | DEBUG_NONE = 0x0000 17 | DEBUG_ENCODER = 0x0001 18 | DEBUG_DECODER = 0x0002 19 | DEBUG_ALL = 0xffff 20 | 21 | FLAG_MAP = { 22 | 'none': DEBUG_NONE, 23 | 'encoder': DEBUG_ENCODER, 24 | 'decoder': DEBUG_DECODER, 25 | 'all': DEBUG_ALL 26 | } 27 | 28 | LOGGEE_MAP = {} 29 | 30 | 31 | class Printer(object): 32 | # noinspection PyShadowingNames 33 | def __init__(self, logger=None, handler=None, formatter=None): 34 | if logger is None: 35 | logger = logging.getLogger('pyasn1') 36 | 37 | logger.setLevel(logging.DEBUG) 38 | 39 | if handler is None: 40 | handler = logging.StreamHandler() 41 | 42 | if formatter is None: 43 | formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') 44 | 45 | handler.setFormatter(formatter) 46 | handler.setLevel(logging.DEBUG) 47 | logger.addHandler(handler) 48 | 49 | self.__logger = logger 50 | 51 | def __call__(self, msg): 52 | self.__logger.debug(msg) 53 | 54 | def __str__(self): 55 | return '' 56 | 57 | 58 | if hasattr(logging, 'NullHandler'): 59 | NullHandler = logging.NullHandler 60 | 61 | else: 62 | # Python 2.6 and older 63 | class NullHandler(logging.Handler): 64 | def emit(self, record): 65 | pass 66 | 67 | 68 | class Debug(object): 69 | defaultPrinter = Printer() 70 | 71 | def __init__(self, *flags, **options): 72 | self._flags = DEBUG_NONE 73 | 74 | if 'loggerName' in options: 75 | # route our logs to parent logger 76 | self._printer = Printer( 77 | logger=logging.getLogger(options['loggerName']), 78 | handler=NullHandler() 79 | ) 80 | 81 | elif 'printer' in options: 82 | self._printer = options.get('printer') 83 | 84 | else: 85 | self._printer = self.defaultPrinter 86 | 87 | self._printer('running pyasn1 %s, debug flags %s' % (__version__, ', '.join(flags))) 88 | 89 | for flag in flags: 90 | inverse = flag and flag[0] in ('!', '~') 91 | if inverse: 92 | flag = flag[1:] 93 | try: 94 | if inverse: 95 | self._flags &= ~FLAG_MAP[flag] 96 | else: 97 | self._flags |= FLAG_MAP[flag] 98 | except KeyError: 99 | raise error.PyAsn1Error('bad debug flag %s' % flag) 100 | 101 | self._printer("debug category '%s' %s" % (flag, inverse and 'disabled' or 'enabled')) 102 | 103 | def __str__(self): 104 | return 'logger %s, flags %x' % (self._printer, self._flags) 105 | 106 | def __call__(self, msg): 107 | self._printer(msg) 108 | 109 | def __and__(self, flag): 110 | return self._flags & flag 111 | 112 | def __rand__(self, flag): 113 | return flag & self._flags 114 | 115 | _LOG = DEBUG_NONE 116 | 117 | 118 | def setLogger(userLogger): 119 | global _LOG 120 | 121 | if userLogger: 122 | _LOG = userLogger 123 | else: 124 | _LOG = DEBUG_NONE 125 | 126 | # Update registered logging clients 127 | for module, (name, flags) in LOGGEE_MAP.items(): 128 | setattr(module, name, _LOG & flags and _LOG or DEBUG_NONE) 129 | 130 | 131 | def registerLoggee(module, name='LOG', flags=DEBUG_NONE): 132 | LOGGEE_MAP[sys.modules[module]] = name, flags 133 | setLogger(_LOG) 134 | return _LOG 135 | 136 | 137 | def hexdump(octets): 138 | return ' '.join( 139 | ['%s%.2X' % (n % 16 == 0 and ('\n%.5d: ' % n) or '', x) 140 | for n, x in zip(range(len(octets)), octs2ints(octets))] 141 | ) 142 | 143 | 144 | class Scope(object): 145 | def __init__(self): 146 | self._list = [] 147 | 148 | def __str__(self): return '.'.join(self._list) 149 | 150 | def push(self, token): 151 | self._list.append(token) 152 | 153 | def pop(self): 154 | return self._list.pop() 155 | 156 | 157 | scope = Scope() 158 | -------------------------------------------------------------------------------- /womail/womail.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | 6 | import requests 7 | 8 | 9 | class WoMailCheckIn: 10 | def __init__(self, check_item): 11 | self.check_item = check_item 12 | 13 | @staticmethod 14 | def login(womail_url): 15 | try: 16 | url = womail_url 17 | headers = { 18 | "User-Agent": "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3868.400 QQBrowser/10.8.4394.400" 19 | } 20 | res = requests.get(url=url, headers=headers, allow_redirects=False) 21 | set_cookie = res.headers["Set-Cookie"] 22 | cookies = re.findall("YZKF_SESSION.*?;", set_cookie)[0] 23 | if "YZKF_SESSION" in cookies: 24 | return cookies 25 | else: 26 | print("沃邮箱获取 cookies 失败") 27 | return None 28 | except Exception as e: 29 | print("沃邮箱错误:", e) 30 | return None 31 | 32 | @staticmethod 33 | def dotask(cookies): 34 | msg = "" 35 | headers = { 36 | "User-Agent": "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3868.400 QQBrowser/10.8.4394.400", 37 | "Cookie": cookies, 38 | } 39 | try: 40 | url = "https://nyan.mail.wo.cn/cn/sign/index/userinfo.do?rand=0.8897817905278955" 41 | res = requests.post(url=url, headers=headers) 42 | result = res.json() 43 | wxName = result.get("result").get("wxName") 44 | userMobile = result.get("result").get("userMobile") 45 | userdata = f"帐号信息: {wxName} - {userMobile[:3]}****{userMobile[-4:]}\n" 46 | msg += userdata 47 | except Exception as e: 48 | print("沃邮箱获取用户信息失败", e) 49 | msg += "沃邮箱获取用户信息失败\n" 50 | try: 51 | url = "https://nyan.mail.wo.cn/cn/sign/user/checkin.do?rand=0.913524814493383" 52 | res = requests.post(url=url, headers=headers).json() 53 | result = res.get("result") 54 | if result == -2: 55 | msg += "每日签到: 已签到\n" 56 | elif result is None: 57 | msg += f"每日签到: 签到失败\n" 58 | else: 59 | msg += f"每日签到: 签到成功~已签到{result}天!\n" 60 | except Exception as e: 61 | print("沃邮箱签到错误", e) 62 | msg += "沃邮箱签到错误\n" 63 | try: 64 | url = "https://nyan.mail.wo.cn/cn/sign/user/doTask.do?rand=0.8776674762904109" 65 | data_params = { 66 | "每日首次登录手机邮箱": {"taskName": "loginmail"}, 67 | "和WOWO熊一起寻宝": {"taskName": "treasure"}, 68 | "去用户俱乐部逛一逛": {"taskName": "club"}, 69 | } 70 | for key, data in dict.items(data_params): 71 | try: 72 | res = requests.post(url=url, data=data, headers=headers).json() 73 | result = res.get("result") 74 | if result == 1: 75 | msg += f"{key}: 做任务成功\n" 76 | elif result == -1: 77 | msg += f"{key}: 任务已做过\n" 78 | elif result == -2: 79 | msg += f"{key}: 请检查登录状态\n" 80 | else: 81 | msg += f"{key}: 未知错误\n" 82 | except Exception as e: 83 | print(f"沃邮箱执行任务【{key}】错误", e) 84 | msg += f"沃邮箱执行任务【{key}】错误" 85 | 86 | except Exception as e: 87 | print("沃邮箱执行任务错误", e) 88 | msg += "沃邮箱执行任务错误错误" 89 | return msg 90 | 91 | def main(self): 92 | womail_url = self.check_item.get("womail_url") 93 | try: 94 | cookies = self.login(womail_url) 95 | if cookies: 96 | msg = self.dotask(cookies) 97 | else: 98 | msg = "登录失败" 99 | except Exception as e: 100 | print(e) 101 | msg = "登录失败" 102 | return msg 103 | 104 | 105 | if __name__ == "__main__": 106 | with open( 107 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 108 | ) as f: 109 | datas = json.loads(f.read()) 110 | _check_item = datas.get("WOMAIL_URL_LIST", [])[1] 111 | print(WoMailCheckIn(check_item=_check_item).main()) 112 | -------------------------------------------------------------------------------- /rsa/pem.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Functions that load and write PEM-encoded files.""" 16 | 17 | import base64 18 | import typing 19 | 20 | # Should either be ASCII strings or bytes. 21 | FlexiText = typing.Union[str, bytes] 22 | 23 | 24 | def _markers(pem_marker: FlexiText) -> typing.Tuple[bytes, bytes]: 25 | """ 26 | Returns the start and end PEM markers, as bytes. 27 | """ 28 | 29 | if not isinstance(pem_marker, bytes): 30 | pem_marker = pem_marker.encode('ascii') 31 | 32 | return (b'-----BEGIN ' + pem_marker + b'-----', 33 | b'-----END ' + pem_marker + b'-----') 34 | 35 | 36 | def _pem_lines(contents: bytes, pem_start: bytes, pem_end: bytes) -> typing.Iterator[bytes]: 37 | """Generator over PEM lines between pem_start and pem_end.""" 38 | 39 | in_pem_part = False 40 | seen_pem_start = False 41 | 42 | for line in contents.splitlines(): 43 | line = line.strip() 44 | 45 | # Skip empty lines 46 | if not line: 47 | continue 48 | 49 | # Handle start marker 50 | if line == pem_start: 51 | if in_pem_part: 52 | raise ValueError('Seen start marker "%r" twice' % pem_start) 53 | 54 | in_pem_part = True 55 | seen_pem_start = True 56 | continue 57 | 58 | # Skip stuff before first marker 59 | if not in_pem_part: 60 | continue 61 | 62 | # Handle end marker 63 | if in_pem_part and line == pem_end: 64 | in_pem_part = False 65 | break 66 | 67 | # Load fields 68 | if b':' in line: 69 | continue 70 | 71 | yield line 72 | 73 | # Do some sanity checks 74 | if not seen_pem_start: 75 | raise ValueError('No PEM start marker "%r" found' % pem_start) 76 | 77 | if in_pem_part: 78 | raise ValueError('No PEM end marker "%r" found' % pem_end) 79 | 80 | 81 | def load_pem(contents: FlexiText, pem_marker: FlexiText) -> bytes: 82 | """Loads a PEM file. 83 | 84 | :param contents: the contents of the file to interpret 85 | :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' 86 | when your file has '-----BEGIN RSA PRIVATE KEY-----' and 87 | '-----END RSA PRIVATE KEY-----' markers. 88 | 89 | :return: the base64-decoded content between the start and end markers. 90 | 91 | @raise ValueError: when the content is invalid, for example when the start 92 | marker cannot be found. 93 | 94 | """ 95 | 96 | # We want bytes, not text. If it's text, it can be converted to ASCII bytes. 97 | if not isinstance(contents, bytes): 98 | contents = contents.encode('ascii') 99 | 100 | (pem_start, pem_end) = _markers(pem_marker) 101 | pem_lines = [line for line in _pem_lines(contents, pem_start, pem_end)] 102 | 103 | # Base64-decode the contents 104 | pem = b''.join(pem_lines) 105 | return base64.standard_b64decode(pem) 106 | 107 | 108 | def save_pem(contents: bytes, pem_marker: FlexiText) -> bytes: 109 | """Saves a PEM file. 110 | 111 | :param contents: the contents to encode in PEM format 112 | :param pem_marker: the marker of the PEM content, such as 'RSA PRIVATE KEY' 113 | when your file has '-----BEGIN RSA PRIVATE KEY-----' and 114 | '-----END RSA PRIVATE KEY-----' markers. 115 | 116 | :return: the base64-encoded content between the start and end markers, as bytes. 117 | 118 | """ 119 | 120 | (pem_start, pem_end) = _markers(pem_marker) 121 | 122 | b64 = base64.standard_b64encode(contents).replace(b'\n', b'') 123 | pem_lines = [pem_start] 124 | 125 | for block_start in range(0, len(b64), 64): 126 | block = b64[block_start:block_start + 64] 127 | pem_lines.append(block) 128 | 129 | pem_lines.append(pem_end) 130 | pem_lines.append(b'') 131 | 132 | return b'\n'.join(pem_lines) 133 | -------------------------------------------------------------------------------- /oneplusbbs/oneplusbbs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | import time 6 | from urllib import parse 7 | 8 | import requests 9 | 10 | 11 | class OnePlusBBSCheckIn: 12 | def __init__(self, check_item): 13 | self.check_item = check_item 14 | 15 | @staticmethod 16 | def sign(cookie): 17 | headers = { 18 | "Origin": "https://www.oneplusbbs.com", 19 | "Content-Type": "application/x-www-form-urlencoded", 20 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57", 21 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", 22 | "Referer": "https://www.oneplusbbs.com/plugin-dsu_paulsign:sign.html", 23 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,fr;q=0.5,pl;q=0.4", 24 | "cookie": cookie, 25 | } 26 | params = ( 27 | ("id", "dsu_paulsign:sign"), 28 | ("operation", "qiandao"), 29 | ("infloat", "1"), 30 | ("inajax", "1"), 31 | ) 32 | formhash = re.findall(r"bbs_formhash=(.*?);", cookie)[0] 33 | data = {"formhash": formhash, "qdxq": "kx", "qdmode": "1", "todaysay": "努力奋斗"} 34 | response = requests.post( 35 | url="https://www.oneplusbbs.com/plugin.php", headers=headers, params=params, data=data 36 | ).text 37 | msg = re.findall(r'
(.*?)
', response, re.S) 38 | msg = msg[0].strip() if msg else "Cookie 可能过期" 39 | return msg 40 | 41 | @staticmethod 42 | def draw(cookie): 43 | headers = { 44 | "Accept": "application/json, text/javascript, */*; q=0.01", 45 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.57", 46 | "X-Requested-With": "XMLHttpRequest", 47 | "Origin": "https://www.oneplusbbs.com", 48 | "Referer": "https://www.oneplusbbs.com/plugin-choujiang.html", 49 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,fr;q=0.5,pl;q=0.4", 50 | "cookie": cookie, 51 | } 52 | params = ( 53 | ("id", "choujiang"), 54 | ("do", "draw"), 55 | ) 56 | sum_list = [] 57 | success_count = 0 58 | error_count = 0 59 | for i in range(10): 60 | try: 61 | data = requests.post(url="https://www.oneplusbbs.com/plugin.php", headers=headers, params=params).json() 62 | if data["ret"] != "": 63 | ret_map = { 64 | "2": 18, 65 | "4": 188, 66 | "5": 88, 67 | "7": 8, 68 | } 69 | ret = data["ret"] 70 | sum_list.append(ret_map.get(ret, 0)) 71 | one_msg = data["msg"] 72 | if str(ret) in ["-1", "-6", "-7"]: 73 | break 74 | else: 75 | success_count += 1 76 | else: 77 | error_count += 1 78 | one_msg = "抽奖失败" 79 | except Exception as e: 80 | one_msg = f"抽奖失败: {e}" 81 | error_count += 1 82 | print(f"第{i + 1}次抽奖结果:" + str(one_msg)) 83 | time.sleep(5) 84 | msg = f"成功抽奖 {success_count} 次" 85 | draw_msg = "抽奖状态: " + str(msg) 86 | draw_msg += f"\n抽奖结果: 获得 {sum(sum_list) - success_count * 10} 加油" 87 | print(draw_msg) 88 | return draw_msg 89 | 90 | def main(self): 91 | oneplusbbs_cookie = self.check_item.get("oneplusbbs_cookie") 92 | bbs_uname = re.findall(r"bbs_uname=(.*?);", oneplusbbs_cookie) 93 | bbs_uname = bbs_uname[0].split("%7C")[0] if bbs_uname else "未获取到用户信息" 94 | try: 95 | bbs_uname = parse.unquote(bbs_uname) 96 | except Exception as e: 97 | print(f"bbs_uname 转换失败: {e}") 98 | bbs_uname = bbs_uname 99 | sign_msg = self.sign(cookie=oneplusbbs_cookie) 100 | draw_msg = self.draw(cookie=oneplusbbs_cookie) 101 | msg = f"帐号信息: {bbs_uname}\n签到信息: {sign_msg}\n{draw_msg}" 102 | return msg 103 | 104 | 105 | if __name__ == "__main__": 106 | with open( 107 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 108 | ) as f: 109 | datas = json.loads(f.read()) 110 | _check_item = datas.get("ONEPLUSBBS_COOKIE_LIST", [])[0] 111 | print(OnePlusBBSCheckIn(check_item=_check_item).main()) 112 | -------------------------------------------------------------------------------- /vqq/vqq.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | import re 5 | import time 6 | from urllib import parse 7 | 8 | import requests 9 | from requests import utils 10 | 11 | 12 | class VQQCheckIn: 13 | def __init__(self, check_item): 14 | self.check_item = check_item 15 | 16 | @staticmethod 17 | def refresh_cookie(url, headers, cookies): 18 | login = requests.get(url=url, headers=headers, cookies=cookies) 19 | nick = re.findall(r'nick":"(.*?)"', login.text) 20 | if nick: 21 | nick = nick[0] 22 | try: 23 | nick = parse.unquote(nick) 24 | except Exception as e: 25 | print(f"nick 转换失败: {e}") 26 | else: 27 | nick = "未获取到用户" 28 | cookie = requests.utils.dict_from_cookiejar(login.cookies) 29 | return cookie, nick 30 | 31 | @staticmethod 32 | def sign_once(headers, cookies): 33 | url = "http://v.qq.com/x/bu/mobile_checkin?isDarkMode=0&uiType=REGULAR" 34 | res = requests.get(url=url, headers=headers, cookies=cookies) 35 | res.encoding = "utf8" 36 | match = re.search(r'isMultiple" />\s+(.*?)\s+<', res.text) 37 | if "isMultiple" in res.text: 38 | try: 39 | value = match.group(1) 40 | except Exception as e: 41 | print(res.text) 42 | value = "数据获取失败" 43 | msg = f"成长值x{value}" 44 | elif "Unauthorized" in res.text: 45 | msg = "cookie 失效" 46 | else: 47 | msg = "签到失败(可能已签到)\n签到失败: 自行在腾讯视频APP内登录网址签到 http://v.qq.com/x/bu/mobile_checkin (基本每周都需要手动签到一次才可以)" 48 | return msg 49 | 50 | @staticmethod 51 | def sign_twice(headers, cookies): 52 | this_time = int(round(time.time() * 1000)) 53 | url = "https://vip.video.qq.com/fcgi-bin/comm_cgi?name=hierarchical_task_system&cmd=2&_=" + str(this_time) 54 | res = requests.get(url=url, headers=headers, cookies=cookies) 55 | res.encoding = "utf8" 56 | if "Account Verify Error" in res.text: 57 | msg = "签到失败-Cookie失效" 58 | elif "Not VIP" in res.text: 59 | msg = "非会员无法签到" 60 | else: 61 | try: 62 | value = re.search('checkin_score": (.*?),', res.text).group(1) 63 | except Exception as e: 64 | print("获取成长值失败", e) 65 | value = res.text 66 | msg = f"成长值x{value}" 67 | return msg 68 | 69 | @staticmethod 70 | def tasks(headers, cookies): 71 | task_map = { 72 | "1": "观看视频60min", 73 | "3": "使用弹幕特权", 74 | "6": "使用赠片特权", 75 | "7": "使用下载特权", 76 | } 77 | task_msg_list = [] 78 | for task_id, task_name in task_map.items(): 79 | this_time = int(round(time.time() * 1000)) 80 | url = f"https://vip.video.qq.com/fcgi-bin/comm_cgi?name=spp_MissionFaHuo&cmd=4&task_id={task_id}&_=${this_time}" 81 | res = requests.get(url=url, headers=headers, cookies=cookies) 82 | res.encoding = "utf8" 83 | if "score" in res.text: 84 | msg = f"获得+10成长值" 85 | elif "已发过货" in res.text: 86 | msg = "任务已完成" 87 | elif "任务未完成" in res.text: 88 | msg = "任务未完成,需手动完成任务" 89 | else: 90 | msg = res.text 91 | task_msg_list.append(f"{task_name}: {msg}") 92 | time.sleep(1) 93 | return "\n".join(task_msg_list) 94 | 95 | def main(self): 96 | auth_refresh = self.check_item.get("auth_refresh") 97 | if not auth_refresh: 98 | return "参数错误: 缺少 auth_refresh 参数,请查看配置文档" 99 | vqq_cookie = {item.split("=")[0]: item.split("=")[1] for item in self.check_item.get("vqq_cookie").split("; ")} 100 | headers = { 101 | "Referer": "https://v.qq.com", 102 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.204 Safari/537.36", 103 | } 104 | login_cookie, nick = self.refresh_cookie(url=auth_refresh, headers=headers, cookies=vqq_cookie) 105 | if login_cookie.get("main_login") == "qq": 106 | vqq_cookie["vqq_vusession"] = login_cookie.get("vqq_vusession") 107 | else: 108 | vqq_cookie["vusession"] = login_cookie.get("vusession") 109 | vqq_cookie["access_token"] = login_cookie.get("access_token") 110 | sign_once_msg = self.sign_once(headers=headers, cookies=vqq_cookie) 111 | sign_twice_msg = self.sign_twice(headers=headers, cookies=vqq_cookie) 112 | task_msg = self.tasks(headers=headers, cookies=vqq_cookie) 113 | msg = f"用户信息: {nick}\n签到奖励1: {sign_once_msg}\n签到奖励2: {sign_twice_msg}\n{task_msg}" 114 | return msg 115 | 116 | 117 | if __name__ == "__main__": 118 | with open( 119 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 120 | ) as f: 121 | datas = json.loads(f.read()) 122 | _check_item = datas.get("VQQ_COOKIE_LIST", [])[0] 123 | print(VQQCheckIn(check_item=_check_item).main()) 124 | -------------------------------------------------------------------------------- /rsa/common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Common functionality shared by several modules.""" 16 | 17 | import typing 18 | 19 | 20 | class NotRelativePrimeError(ValueError): 21 | def __init__(self, a: int, b: int, d: int, msg: str = '') -> None: 22 | super().__init__(msg or "%d and %d are not relatively prime, divider=%i" % (a, b, d)) 23 | self.a = a 24 | self.b = b 25 | self.d = d 26 | 27 | 28 | def bit_size(num: int) -> int: 29 | """ 30 | Number of bits needed to represent a integer excluding any prefix 31 | 0 bits. 32 | 33 | Usage:: 34 | 35 | >>> bit_size(1023) 36 | 10 37 | >>> bit_size(1024) 38 | 11 39 | >>> bit_size(1025) 40 | 11 41 | 42 | :param num: 43 | Integer value. If num is 0, returns 0. Only the absolute value of the 44 | number is considered. Therefore, signed integers will be abs(num) 45 | before the number's bit length is determined. 46 | :returns: 47 | Returns the number of bits in the integer. 48 | """ 49 | 50 | try: 51 | return num.bit_length() 52 | except AttributeError: 53 | raise TypeError('bit_size(num) only supports integers, not %r' % type(num)) 54 | 55 | 56 | def byte_size(number: int) -> int: 57 | """ 58 | Returns the number of bytes required to hold a specific long number. 59 | 60 | The number of bytes is rounded up. 61 | 62 | Usage:: 63 | 64 | >>> byte_size(1 << 1023) 65 | 128 66 | >>> byte_size((1 << 1024) - 1) 67 | 128 68 | >>> byte_size(1 << 1024) 69 | 129 70 | 71 | :param number: 72 | An unsigned integer 73 | :returns: 74 | The number of bytes required to hold a specific long number. 75 | """ 76 | if number == 0: 77 | return 1 78 | return ceil_div(bit_size(number), 8) 79 | 80 | 81 | def ceil_div(num: int, div: int) -> int: 82 | """ 83 | Returns the ceiling function of a division between `num` and `div`. 84 | 85 | Usage:: 86 | 87 | >>> ceil_div(100, 7) 88 | 15 89 | >>> ceil_div(100, 10) 90 | 10 91 | >>> ceil_div(1, 4) 92 | 1 93 | 94 | :param num: Division's numerator, a number 95 | :param div: Division's divisor, a number 96 | 97 | :return: Rounded up result of the division between the parameters. 98 | """ 99 | quanta, mod = divmod(num, div) 100 | if mod: 101 | quanta += 1 102 | return quanta 103 | 104 | 105 | def extended_gcd(a: int, b: int) -> typing.Tuple[int, int, int]: 106 | """Returns a tuple (r, i, j) such that r = gcd(a, b) = ia + jb 107 | """ 108 | # r = gcd(a,b) i = multiplicitive inverse of a mod b 109 | # or j = multiplicitive inverse of b mod a 110 | # Neg return values for i or j are made positive mod b or a respectively 111 | # Iterateive Version is faster and uses much less stack space 112 | x = 0 113 | y = 1 114 | lx = 1 115 | ly = 0 116 | oa = a # Remember original a/b to remove 117 | ob = b # negative values from return results 118 | while b != 0: 119 | q = a // b 120 | (a, b) = (b, a % b) 121 | (x, lx) = ((lx - (q * x)), x) 122 | (y, ly) = ((ly - (q * y)), y) 123 | if lx < 0: 124 | lx += ob # If neg wrap modulo orignal b 125 | if ly < 0: 126 | ly += oa # If neg wrap modulo orignal a 127 | return a, lx, ly # Return only positive values 128 | 129 | 130 | def inverse(x: int, n: int) -> int: 131 | """Returns the inverse of x % n under multiplication, a.k.a x^-1 (mod n) 132 | 133 | >>> inverse(7, 4) 134 | 3 135 | >>> (inverse(143, 4) * 143) % 4 136 | 1 137 | """ 138 | 139 | (divider, inv, _) = extended_gcd(x, n) 140 | 141 | if divider != 1: 142 | raise NotRelativePrimeError(x, n, divider) 143 | 144 | return inv 145 | 146 | 147 | def crt(a_values: typing.Iterable[int], modulo_values: typing.Iterable[int]) -> int: 148 | """Chinese Remainder Theorem. 149 | 150 | Calculates x such that x = a[i] (mod m[i]) for each i. 151 | 152 | :param a_values: the a-values of the above equation 153 | :param modulo_values: the m-values of the above equation 154 | :returns: x such that x = a[i] (mod m[i]) for each i 155 | 156 | 157 | >>> crt([2, 3], [3, 5]) 158 | 8 159 | 160 | >>> crt([2, 3, 2], [3, 5, 7]) 161 | 23 162 | 163 | >>> crt([2, 3, 0], [7, 11, 15]) 164 | 135 165 | """ 166 | 167 | m = 1 168 | x = 0 169 | 170 | for modulo in modulo_values: 171 | m *= modulo 172 | 173 | for (m_i, a_i) in zip(modulo_values, a_values): 174 | M_i = m // m_i 175 | inv = inverse(M_i, m_i) 176 | 177 | x = (x + a_i * M_i * inv) % m 178 | 179 | return x 180 | 181 | 182 | if __name__ == '__main__': 183 | import doctest 184 | 185 | doctest.testmod() 186 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | from acfun import AcFunCheckIn 6 | from baidu_url_submit import BaiduUrlSubmit 7 | from bilibili import BiliBiliCheckIn 8 | from cloud189 import Cloud189CheckIn 9 | from csdn import CSDNCheckIn 10 | from duokan import DuoKanCheckIn 11 | from fmapp import FMAPPCheckIn 12 | from iqiyi import IQIYICheckIn 13 | from kgqq import KGQQCheckIn 14 | from liantong import LianTongCheckIn 15 | from meizu import MeizuCheckIn 16 | from mgtv import MgtvCheckIn 17 | from mimotion import MiMotion 18 | from music163 import Music163CheckIn 19 | from oneplusbbs import OnePlusBBSCheckIn 20 | from picacomic import PicacomicCheckIn 21 | from pojie import PojieCheckIn 22 | from smzdm import SmzdmCheckIn 23 | from tieba import TiebaCheckIn 24 | from v2ex import V2exCheckIn 25 | from vqq import VQQCheckIn 26 | from weather import Weather 27 | from weibo import WeiBoCheckIn 28 | from womail import WoMailCheckIn 29 | from wps import WPSCheckIn 30 | from www2nzz import WWW2nzzCheckIn 31 | from wzyd import WZYDCheckIn 32 | from youdao import YouDaoCheckIn 33 | from zhiyoo import ZhiyooCheckIn 34 | 35 | checkin_map = { 36 | "IQIYI_COOKIE_LIST": ("爱奇艺", IQIYICheckIn), 37 | "VQQ_COOKIE_LIST": ("腾讯视频", VQQCheckIn), 38 | "MGTV_PARAMS_LIST": ("芒果TV", MgtvCheckIn), 39 | "KGQQ_COOKIE_LIST": ("全民K歌", KGQQCheckIn), 40 | "MUSIC163_ACCOUNT_LIST": ("网易云音乐", Music163CheckIn), 41 | "BILIBILI_COOKIE_LIST": ("Bilibili", BiliBiliCheckIn), 42 | "YOUDAO_COOKIE_LIST": ("有道云笔记", YouDaoCheckIn), 43 | "FMAPP_ACCOUNT_LIST": ("Fa米家 APP", FMAPPCheckIn), 44 | "BAIDU_URL_SUBMIT_LIST": ("百度站点提交", BaiduUrlSubmit), 45 | "LIANTONG_ACCOUNT_LIST": ("联通营业厅", LianTongCheckIn), 46 | "ONEPLUSBBS_COOKIE_LIST": ("一加手机社区官方论坛", OnePlusBBSCheckIn), 47 | "SMZDM_COOKIE_LIST": ("什么值得买", SmzdmCheckIn), 48 | "TIEBA_COOKIE_LIST": ("百度贴吧", TiebaCheckIn), 49 | "V2EX_COOKIE_LIST": ("V2EX 论坛", V2exCheckIn), 50 | "WWW2NZZ_COOKIE_LIST": ("咔叽网单", WWW2nzzCheckIn), 51 | "ACFUN_ACCOUNT_LIST": ("AcFun", AcFunCheckIn), 52 | "MIMOTION_ACCOUNT_LIST": ("小米运动", MiMotion), 53 | "CLOUD189_ACCOUNT_LIST": ("天翼云盘", Cloud189CheckIn), 54 | "WPS_COOKIE_LIST": ("WPS", WPSCheckIn), 55 | "POJIE_COOKIE_LIST": ("吾爱破解", PojieCheckIn), 56 | "MEIZU_COOKIE_LIST": ("MEIZU社区", MeizuCheckIn), 57 | "PICACOMIC_ACCOUNT_LIST": ("哔咔漫画", PicacomicCheckIn), 58 | "ZHIYOO_COOKIE_LIST": ("智友邦", ZhiyooCheckIn), 59 | "WEIBO_COOKIE_LIST": ("微博", WeiBoCheckIn), 60 | "DUOKAN_COOKIE_LIST": ("多看阅读", DuoKanCheckIn), 61 | "CSDN_COOKIE_LIST": ("CSDN", CSDNCheckIn), 62 | "WZYD_DATA_LIST": ("王者营地", WZYDCheckIn), 63 | "WOMAIL_URL_LIST": ("沃邮箱", WoMailCheckIn), 64 | "CITY_NAME_LIST": ("天气预报", Weather), 65 | } 66 | 67 | notice_map = { 68 | "DINGTALK_SECRET": "", 69 | "DINGTALK_ACCESS_TOKEN": "", 70 | "BARK_URL": "", 71 | "SCKEY": "", 72 | "SENDKEY": "", 73 | "TG_BOT_TOKEN": "", 74 | "TG_USER_ID": "", 75 | "QMSG_KEY": "", 76 | "QMSG_TYPE": "", 77 | "COOLPUSHSKEY": "", 78 | "COOLPUSHQQ": "", 79 | "COOLPUSHWX": "", 80 | "COOLPUSHEMAIL": "", 81 | "QYWX_KEY": "", 82 | "QYWX_CORPID": "", 83 | "QYWX_AGENTID": "", 84 | "QYWX_CORPSECRET": "", 85 | "QYWX_TOUSER": "", 86 | "PUSHPLUS_TOKEN": "", 87 | "PUSHPLUS_TOPIC": "", 88 | } 89 | 90 | 91 | def env2list(key): 92 | try: 93 | value = json.loads(os.getenv(key, []).strip()) if os.getenv(key) else [] 94 | if isinstance(value, list): 95 | value = value 96 | else: 97 | value = [] 98 | except Exception as e: 99 | print(e) 100 | value = [] 101 | return value 102 | 103 | 104 | def env2config(save_file=False): 105 | result = json.loads(os.getenv("CONFIG_JSON", {}).strip()) if os.getenv("CONFIG_JSON") else {} 106 | for one in checkin_map.keys(): 107 | if one not in result.keys(): 108 | result[one] = [] 109 | check_items = env2list(one) 110 | result[one] += check_items 111 | for one in notice_map.keys(): 112 | if not result.get(one): 113 | if env2str(one): 114 | result[one] = env2str(one) 115 | if not result.get("MOTTO"): 116 | result["MOTTO"] = os.getenv("MOTTO") 117 | if save_file: 118 | with open(os.path.join(os.path.dirname(__file__), "config/config.json"), "w+") as f: 119 | f.write(json.dumps(result)) 120 | return result 121 | 122 | 123 | def env2str(key): 124 | try: 125 | value = os.getenv(key, "") if os.getenv(key) else "" 126 | if isinstance(value, str): 127 | value = value.strip() 128 | elif isinstance(value, bool): 129 | value = value 130 | else: 131 | value = None 132 | except Exception as e: 133 | print(e) 134 | value = None 135 | return value 136 | 137 | 138 | def get_checkin_info(data): 139 | result = {} 140 | if isinstance(data, dict): 141 | for one in checkin_map.keys(): 142 | result[one.lower()] = data.get(one, []) 143 | else: 144 | for one in checkin_map.keys(): 145 | result[one.lower()] = env2list(one) 146 | return result 147 | 148 | 149 | def get_notice_info(data): 150 | result = {} 151 | if isinstance(data, dict): 152 | for one in notice_map.keys(): 153 | result[one.lower()] = data.get(one, None) 154 | else: 155 | for one in notice_map.keys(): 156 | result[one.lower()] = env2str(one) 157 | return result 158 | 159 | 160 | if __name__ == "__main__": 161 | env2config(save_file=True) 162 | -------------------------------------------------------------------------------- /rsa/bigfile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2011 Sybren A. Stüvel 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """Large file support 18 | 19 | .. deprecated:: 3.4 20 | 21 | The VARBLOCK format is NOT recommended for general use, has been deprecated since 22 | Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a 23 | number of attacks: 24 | 25 | 1. decrypt/encrypt_bigfile() does not implement `Authenticated encryption`_ nor 26 | uses MACs to verify messages before decrypting public key encrypted messages. 27 | 28 | 2. decrypt/encrypt_bigfile() does not use hybrid encryption (it uses plain RSA) 29 | and has no method for chaining, so block reordering is possible. 30 | 31 | See `issue #19 on Github`_ for more information. 32 | 33 | .. _Authenticated encryption: https://en.wikipedia.org/wiki/Authenticated_encryption 34 | .. _issue #19 on Github: https://github.com/sybrenstuvel/python-rsa/issues/13 35 | 36 | 37 | This module contains functions to: 38 | 39 | - break a file into smaller blocks, and encrypt them, and store the 40 | encrypted blocks in another file. 41 | 42 | - take such an encrypted files, decrypt its blocks, and reconstruct the 43 | original file. 44 | 45 | The encrypted file format is as follows, where || denotes byte concatenation: 46 | 47 | FILE := VERSION || BLOCK || BLOCK ... 48 | 49 | BLOCK := LENGTH || DATA 50 | 51 | LENGTH := varint-encoded length of the subsequent data. Varint comes from 52 | Google Protobuf, and encodes an integer into a variable number of bytes. 53 | Each byte uses the 7 lowest bits to encode the value. The highest bit set 54 | to 1 indicates the next byte is also part of the varint. The last byte will 55 | have this bit set to 0. 56 | 57 | This file format is called the VARBLOCK format, in line with the varint format 58 | used to denote the block sizes. 59 | 60 | """ 61 | 62 | import warnings 63 | 64 | from rsa import key, common, pkcs1, varblock 65 | from rsa._compat import byte 66 | 67 | 68 | def encrypt_bigfile(infile, outfile, pub_key): 69 | """Encrypts a file, writing it to 'outfile' in VARBLOCK format. 70 | 71 | .. deprecated:: 3.4 72 | This function was deprecated in Python-RSA version 3.4 due to security issues 73 | in the VARBLOCK format. See the documentation_ for more information. 74 | 75 | .. _documentation: https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files 76 | 77 | :param infile: file-like object to read the cleartext from 78 | :param outfile: file-like object to write the crypto in VARBLOCK format to 79 | :param pub_key: :py:class:`rsa.PublicKey` to encrypt with 80 | 81 | """ 82 | 83 | warnings.warn("The 'rsa.bigfile.encrypt_bigfile' function was deprecated in Python-RSA version " 84 | "3.4 due to security issues in the VARBLOCK format. See " 85 | "https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files " 86 | "for more information.", 87 | DeprecationWarning, stacklevel=2) 88 | 89 | if not isinstance(pub_key, key.PublicKey): 90 | raise TypeError('Public key required, but got %r' % pub_key) 91 | 92 | key_bytes = common.bit_size(pub_key.n) // 8 93 | blocksize = key_bytes - 11 # keep space for PKCS#1 padding 94 | 95 | # Write the version number to the VARBLOCK file 96 | outfile.write(byte(varblock.VARBLOCK_VERSION)) 97 | 98 | # Encrypt and write each block 99 | for block in varblock.yield_fixedblocks(infile, blocksize): 100 | crypto = pkcs1.encrypt(block, pub_key) 101 | 102 | varblock.write_varint(outfile, len(crypto)) 103 | outfile.write(crypto) 104 | 105 | 106 | def decrypt_bigfile(infile, outfile, priv_key): 107 | """Decrypts an encrypted VARBLOCK file, writing it to 'outfile' 108 | 109 | .. deprecated:: 3.4 110 | This function was deprecated in Python-RSA version 3.4 due to security issues 111 | in the VARBLOCK format. See the documentation_ for more information. 112 | 113 | .. _documentation: https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files 114 | 115 | :param infile: file-like object to read the crypto in VARBLOCK format from 116 | :param outfile: file-like object to write the cleartext to 117 | :param priv_key: :py:class:`rsa.PrivateKey` to decrypt with 118 | 119 | """ 120 | 121 | warnings.warn("The 'rsa.bigfile.decrypt_bigfile' function was deprecated in Python-RSA version " 122 | "3.4 due to security issues in the VARBLOCK format. See " 123 | "https://stuvel.eu/python-rsa-doc/usage.html#working-with-big-files " 124 | "for more information.", 125 | DeprecationWarning, stacklevel=2) 126 | 127 | if not isinstance(priv_key, key.PrivateKey): 128 | raise TypeError('Private key required, but got %r' % priv_key) 129 | 130 | for block in varblock.yield_varblocks(infile): 131 | cleartext = pkcs1.decrypt(block, priv_key) 132 | outfile.write(cleartext) 133 | 134 | 135 | __all__ = ['encrypt_bigfile', 'decrypt_bigfile'] 136 | -------------------------------------------------------------------------------- /pyasn1/type/namedval.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | # ASN.1 named integers 8 | # 9 | from pyasn1 import error 10 | 11 | __all__ = ['NamedValues'] 12 | 13 | 14 | class NamedValues(object): 15 | """Create named values object. 16 | 17 | The |NamedValues| object represents a collection of string names 18 | associated with numeric IDs. These objects are used for giving 19 | names to otherwise numerical values. 20 | 21 | |NamedValues| objects are immutable and duck-type Python 22 | :class:`dict` object mapping ID to name and vice-versa. 23 | 24 | Parameters 25 | ---------- 26 | *args: variable number of two-element :py:class:`tuple` 27 | 28 | name: :py:class:`str` 29 | Value label 30 | 31 | value: :py:class:`int` 32 | Numeric value 33 | 34 | Keyword Args 35 | ------------ 36 | name: :py:class:`str` 37 | Value label 38 | 39 | value: :py:class:`int` 40 | Numeric value 41 | 42 | Examples 43 | -------- 44 | 45 | .. code-block:: pycon 46 | 47 | >>> nv = NamedValues('a', 'b', ('c', 0), d=1) 48 | >>> nv 49 | >>> {'c': 0, 'd': 1, 'a': 2, 'b': 3} 50 | >>> nv[0] 51 | 'c' 52 | >>> nv['a'] 53 | 2 54 | """ 55 | def __init__(self, *args, **kwargs): 56 | self.__names = {} 57 | self.__numbers = {} 58 | 59 | anonymousNames = [] 60 | 61 | for namedValue in args: 62 | if isinstance(namedValue, (tuple, list)): 63 | try: 64 | name, number = namedValue 65 | 66 | except ValueError: 67 | raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,)) 68 | 69 | else: 70 | anonymousNames.append(namedValue) 71 | continue 72 | 73 | if name in self.__names: 74 | raise error.PyAsn1Error('Duplicate name %s' % (name,)) 75 | 76 | if number in self.__numbers: 77 | raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) 78 | 79 | self.__names[name] = number 80 | self.__numbers[number] = name 81 | 82 | for name, number in kwargs.items(): 83 | if name in self.__names: 84 | raise error.PyAsn1Error('Duplicate name %s' % (name,)) 85 | 86 | if number in self.__numbers: 87 | raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number)) 88 | 89 | self.__names[name] = number 90 | self.__numbers[number] = name 91 | 92 | if anonymousNames: 93 | 94 | number = self.__numbers and max(self.__numbers) + 1 or 0 95 | 96 | for name in anonymousNames: 97 | 98 | if name in self.__names: 99 | raise error.PyAsn1Error('Duplicate name %s' % (name,)) 100 | 101 | self.__names[name] = number 102 | self.__numbers[number] = name 103 | 104 | number += 1 105 | 106 | def __repr__(self): 107 | representation = ', '.join(['%s=%d' % x for x in self.items()]) 108 | 109 | if len(representation) > 64: 110 | representation = representation[:32] + '...' + representation[-32:] 111 | 112 | return '<%s object, enums %s>' % ( 113 | self.__class__.__name__, representation) 114 | 115 | def __eq__(self, other): 116 | return dict(self) == other 117 | 118 | def __ne__(self, other): 119 | return dict(self) != other 120 | 121 | def __lt__(self, other): 122 | return dict(self) < other 123 | 124 | def __le__(self, other): 125 | return dict(self) <= other 126 | 127 | def __gt__(self, other): 128 | return dict(self) > other 129 | 130 | def __ge__(self, other): 131 | return dict(self) >= other 132 | 133 | def __hash__(self): 134 | return hash(self.items()) 135 | 136 | # Python dict protocol (read-only) 137 | 138 | def __getitem__(self, key): 139 | try: 140 | return self.__numbers[key] 141 | 142 | except KeyError: 143 | return self.__names[key] 144 | 145 | def __len__(self): 146 | return len(self.__names) 147 | 148 | def __contains__(self, key): 149 | return key in self.__names or key in self.__numbers 150 | 151 | def __iter__(self): 152 | return iter(self.__names) 153 | 154 | def values(self): 155 | return iter(self.__numbers) 156 | 157 | def keys(self): 158 | return iter(self.__names) 159 | 160 | def items(self): 161 | for name in self.__names: 162 | yield name, self.__names[name] 163 | 164 | # support merging 165 | 166 | def __add__(self, namedValues): 167 | return self.__class__(*tuple(self.items()) + tuple(namedValues.items())) 168 | 169 | # XXX clone/subtype? 170 | 171 | def clone(self, *args, **kwargs): 172 | new = self.__class__(*args, **kwargs) 173 | return self + new 174 | 175 | # legacy protocol 176 | 177 | def getName(self, value): 178 | if value in self.__numbers: 179 | return self.__numbers[value] 180 | 181 | def getValue(self, name): 182 | if name in self.__names: 183 | return self.__names[name] 184 | 185 | def getValues(self, *names): 186 | try: 187 | return [self.__names[name] for name in names] 188 | 189 | except KeyError: 190 | raise error.PyAsn1Error( 191 | 'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),) 192 | ) 193 | -------------------------------------------------------------------------------- /rsa/prime.py: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Sybren A. Stüvel 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Numerical functions related to primes. 16 | 17 | Implementation based on the book Algorithm Design by Michael T. Goodrich and 18 | Roberto Tamassia, 2002. 19 | """ 20 | 21 | import rsa.common 22 | import rsa.randnum 23 | 24 | __all__ = ['getprime', 'are_relatively_prime'] 25 | 26 | 27 | def gcd(p: int, q: int) -> int: 28 | """Returns the greatest common divisor of p and q 29 | 30 | >>> gcd(48, 180) 31 | 12 32 | """ 33 | 34 | while q != 0: 35 | (p, q) = (q, p % q) 36 | return p 37 | 38 | 39 | def get_primality_testing_rounds(number: int) -> int: 40 | """Returns minimum number of rounds for Miller-Rabing primality testing, 41 | based on number bitsize. 42 | 43 | According to NIST FIPS 186-4, Appendix C, Table C.3, minimum number of 44 | rounds of M-R testing, using an error probability of 2 ** (-100), for 45 | different p, q bitsizes are: 46 | * p, q bitsize: 512; rounds: 7 47 | * p, q bitsize: 1024; rounds: 4 48 | * p, q bitsize: 1536; rounds: 3 49 | See: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf 50 | """ 51 | 52 | # Calculate number bitsize. 53 | bitsize = rsa.common.bit_size(number) 54 | # Set number of rounds. 55 | if bitsize >= 1536: 56 | return 3 57 | if bitsize >= 1024: 58 | return 4 59 | if bitsize >= 512: 60 | return 7 61 | # For smaller bitsizes, set arbitrary number of rounds. 62 | return 10 63 | 64 | 65 | def miller_rabin_primality_testing(n: int, k: int) -> bool: 66 | """Calculates whether n is composite (which is always correct) or prime 67 | (which theoretically is incorrect with error probability 4**-k), by 68 | applying Miller-Rabin primality testing. 69 | 70 | For reference and implementation example, see: 71 | https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test 72 | 73 | :param n: Integer to be tested for primality. 74 | :type n: int 75 | :param k: Number of rounds (witnesses) of Miller-Rabin testing. 76 | :type k: int 77 | :return: False if the number is composite, True if it's probably prime. 78 | :rtype: bool 79 | """ 80 | 81 | # prevent potential infinite loop when d = 0 82 | if n < 2: 83 | return False 84 | 85 | # Decompose (n - 1) to write it as (2 ** r) * d 86 | # While d is even, divide it by 2 and increase the exponent. 87 | d = n - 1 88 | r = 0 89 | 90 | while not (d & 1): 91 | r += 1 92 | d >>= 1 93 | 94 | # Test k witnesses. 95 | for _ in range(k): 96 | # Generate random integer a, where 2 <= a <= (n - 2) 97 | a = rsa.randnum.randint(n - 3) + 1 98 | 99 | x = pow(a, d, n) 100 | if x == 1 or x == n - 1: 101 | continue 102 | 103 | for _ in range(r - 1): 104 | x = pow(x, 2, n) 105 | if x == 1: 106 | # n is composite. 107 | return False 108 | if x == n - 1: 109 | # Exit inner loop and continue with next witness. 110 | break 111 | else: 112 | # If loop doesn't break, n is composite. 113 | return False 114 | 115 | return True 116 | 117 | 118 | def is_prime(number: int) -> bool: 119 | """Returns True if the number is prime, and False otherwise. 120 | 121 | >>> is_prime(2) 122 | True 123 | >>> is_prime(42) 124 | False 125 | >>> is_prime(41) 126 | True 127 | """ 128 | 129 | # Check for small numbers. 130 | if number < 10: 131 | return number in {2, 3, 5, 7} 132 | 133 | # Check for even numbers. 134 | if not (number & 1): 135 | return False 136 | 137 | # Calculate minimum number of rounds. 138 | k = get_primality_testing_rounds(number) 139 | 140 | # Run primality testing with (minimum + 1) rounds. 141 | return miller_rabin_primality_testing(number, k + 1) 142 | 143 | 144 | def getprime(nbits: int) -> int: 145 | """Returns a prime number that can be stored in 'nbits' bits. 146 | 147 | >>> p = getprime(128) 148 | >>> is_prime(p-1) 149 | False 150 | >>> is_prime(p) 151 | True 152 | >>> is_prime(p+1) 153 | False 154 | 155 | >>> from rsa import common 156 | >>> common.bit_size(p) == 128 157 | True 158 | """ 159 | 160 | assert nbits > 3 # the loop wil hang on too small numbers 161 | 162 | while True: 163 | integer = rsa.randnum.read_random_odd_int(nbits) 164 | 165 | # Test for primeness 166 | if is_prime(integer): 167 | return integer 168 | 169 | # Retry if not prime 170 | 171 | 172 | def are_relatively_prime(a: int, b: int) -> bool: 173 | """Returns True if a and b are relatively prime, and False if they 174 | are not. 175 | 176 | >>> are_relatively_prime(2, 3) 177 | True 178 | >>> are_relatively_prime(2, 4) 179 | False 180 | """ 181 | 182 | d = gcd(a, b) 183 | return d == 1 184 | 185 | 186 | if __name__ == '__main__': 187 | print('Running doctests 1000x or until failure') 188 | import doctest 189 | 190 | for count in range(1000): 191 | (failures, tests) = doctest.testmod() 192 | if failures: 193 | break 194 | 195 | if count % 100 == 0 and count: 196 | print('%i times' % count) 197 | 198 | print('Doctests done') 199 | -------------------------------------------------------------------------------- /rsa/varblock.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright 2011 Sybren A. Stüvel 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """VARBLOCK file support 18 | 19 | .. deprecated:: 3.4 20 | 21 | The VARBLOCK format is NOT recommended for general use, has been deprecated since 22 | Python-RSA 3.4, and will be removed in a future release. It's vulnerable to a 23 | number of attacks: 24 | 25 | 1. decrypt/encrypt_bigfile() does not implement `Authenticated encryption`_ nor 26 | uses MACs to verify messages before decrypting public key encrypted messages. 27 | 28 | 2. decrypt/encrypt_bigfile() does not use hybrid encryption (it uses plain RSA) 29 | and has no method for chaining, so block reordering is possible. 30 | 31 | See `issue #19 on Github`_ for more information. 32 | 33 | .. _Authenticated encryption: https://en.wikipedia.org/wiki/Authenticated_encryption 34 | .. _issue #19 on Github: https://github.com/sybrenstuvel/python-rsa/issues/13 35 | 36 | 37 | The VARBLOCK file format is as follows, where || denotes byte concatenation: 38 | 39 | FILE := VERSION || BLOCK || BLOCK ... 40 | 41 | BLOCK := LENGTH || DATA 42 | 43 | LENGTH := varint-encoded length of the subsequent data. Varint comes from 44 | Google Protobuf, and encodes an integer into a variable number of bytes. 45 | Each byte uses the 7 lowest bits to encode the value. The highest bit set 46 | to 1 indicates the next byte is also part of the varint. The last byte will 47 | have this bit set to 0. 48 | 49 | This file format is called the VARBLOCK format, in line with the varint format 50 | used to denote the block sizes. 51 | 52 | """ 53 | 54 | import warnings 55 | 56 | from rsa._compat import byte, b 57 | 58 | ZERO_BYTE = b('\x00') 59 | VARBLOCK_VERSION = 1 60 | 61 | warnings.warn("The 'rsa.varblock' module was deprecated in Python-RSA version " 62 | "3.4 due to security issues in the VARBLOCK format. See " 63 | "https://github.com/sybrenstuvel/python-rsa/issues/13 for more information.", 64 | DeprecationWarning) 65 | 66 | 67 | def read_varint(infile): 68 | """Reads a varint from the file. 69 | 70 | When the first byte to be read indicates EOF, (0, 0) is returned. When an 71 | EOF occurs when at least one byte has been read, an EOFError exception is 72 | raised. 73 | 74 | :param infile: the file-like object to read from. It should have a read() 75 | method. 76 | :returns: (varint, length), the read varint and the number of read bytes. 77 | """ 78 | 79 | varint = 0 80 | read_bytes = 0 81 | 82 | while True: 83 | char = infile.read(1) 84 | if len(char) == 0: 85 | if read_bytes == 0: 86 | return 0, 0 87 | raise EOFError('EOF while reading varint, value is %i so far' % 88 | varint) 89 | 90 | byte = ord(char) 91 | varint += (byte & 0x7F) << (7 * read_bytes) 92 | 93 | read_bytes += 1 94 | 95 | if not byte & 0x80: 96 | return varint, read_bytes 97 | 98 | 99 | def write_varint(outfile, value): 100 | """Writes a varint to a file. 101 | 102 | :param outfile: the file-like object to write to. It should have a write() 103 | method. 104 | :returns: the number of written bytes. 105 | """ 106 | 107 | # there is a big difference between 'write the value 0' (this case) and 108 | # 'there is nothing left to write' (the false-case of the while loop) 109 | 110 | if value == 0: 111 | outfile.write(ZERO_BYTE) 112 | return 1 113 | 114 | written_bytes = 0 115 | while value > 0: 116 | to_write = value & 0x7f 117 | value >>= 7 118 | 119 | if value > 0: 120 | to_write |= 0x80 121 | 122 | outfile.write(byte(to_write)) 123 | written_bytes += 1 124 | 125 | return written_bytes 126 | 127 | 128 | def yield_varblocks(infile): 129 | """Generator, yields each block in the input file. 130 | 131 | :param infile: file to read, is expected to have the VARBLOCK format as 132 | described in the module's docstring. 133 | @yields the contents of each block. 134 | """ 135 | 136 | # Check the version number 137 | first_char = infile.read(1) 138 | if len(first_char) == 0: 139 | raise EOFError('Unable to read VARBLOCK version number') 140 | 141 | version = ord(first_char) 142 | if version != VARBLOCK_VERSION: 143 | raise ValueError('VARBLOCK version %i not supported' % version) 144 | 145 | while True: 146 | (block_size, read_bytes) = read_varint(infile) 147 | 148 | # EOF at block boundary, that's fine. 149 | if read_bytes == 0 and block_size == 0: 150 | break 151 | 152 | block = infile.read(block_size) 153 | 154 | read_size = len(block) 155 | if read_size != block_size: 156 | raise EOFError('Block size is %i, but could read only %i bytes' % 157 | (block_size, read_size)) 158 | 159 | yield block 160 | 161 | 162 | def yield_fixedblocks(infile, blocksize): 163 | """Generator, yields each block of ``blocksize`` bytes in the input file. 164 | 165 | :param infile: file to read and separate in blocks. 166 | :returns: a generator that yields the contents of each block 167 | """ 168 | 169 | while True: 170 | block = infile.read(blocksize) 171 | 172 | read_bytes = len(block) 173 | if read_bytes == 0: 174 | break 175 | 176 | yield block 177 | 178 | if read_bytes < blocksize: 179 | break 180 | -------------------------------------------------------------------------------- /pyasn1/type/useful.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of pyasn1 software. 3 | # 4 | # Copyright (c) 2005-2019, Ilya Etingof 5 | # License: http://snmplabs.com/pyasn1/license.html 6 | # 7 | import datetime 8 | 9 | from pyasn1 import error 10 | from pyasn1.compat import dateandtime 11 | from pyasn1.compat import string 12 | from pyasn1.type import char 13 | from pyasn1.type import tag 14 | from pyasn1.type import univ 15 | 16 | __all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] 17 | 18 | NoValue = univ.NoValue 19 | noValue = univ.noValue 20 | 21 | 22 | class ObjectDescriptor(char.GraphicString): 23 | __doc__ = char.GraphicString.__doc__ 24 | 25 | #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 26 | tagSet = char.GraphicString.tagSet.tagImplicitly( 27 | tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) 28 | ) 29 | 30 | # Optimization for faster codec lookup 31 | typeId = char.GraphicString.getTypeId() 32 | 33 | 34 | class TimeMixIn(object): 35 | 36 | _yearsDigits = 4 37 | _hasSubsecond = False 38 | _optionalMinutes = False 39 | _shortTZ = False 40 | 41 | class FixedOffset(datetime.tzinfo): 42 | """Fixed offset in minutes east from UTC.""" 43 | 44 | # defaulted arguments required 45 | # https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html 46 | def __init__(self, offset=0, name='UTC'): 47 | self.__offset = datetime.timedelta(minutes=offset) 48 | self.__name = name 49 | 50 | def utcoffset(self, dt): 51 | return self.__offset 52 | 53 | def tzname(self, dt): 54 | return self.__name 55 | 56 | def dst(self, dt): 57 | return datetime.timedelta(0) 58 | 59 | UTC = FixedOffset() 60 | 61 | @property 62 | def asDateTime(self): 63 | """Create :py:class:`datetime.datetime` object from a |ASN.1| object. 64 | 65 | Returns 66 | ------- 67 | : 68 | new instance of :py:class:`datetime.datetime` object 69 | """ 70 | text = str(self) 71 | if text.endswith('Z'): 72 | tzinfo = TimeMixIn.UTC 73 | text = text[:-1] 74 | 75 | elif '-' in text or '+' in text: 76 | if '+' in text: 77 | text, plusminus, tz = string.partition(text, '+') 78 | else: 79 | text, plusminus, tz = string.partition(text, '-') 80 | 81 | if self._shortTZ and len(tz) == 2: 82 | tz += '00' 83 | 84 | if len(tz) != 4: 85 | raise error.PyAsn1Error('malformed time zone offset %s' % tz) 86 | 87 | try: 88 | minutes = int(tz[:2]) * 60 + int(tz[2:]) 89 | if plusminus == '-': 90 | minutes *= -1 91 | 92 | except ValueError: 93 | raise error.PyAsn1Error('unknown time specification %s' % self) 94 | 95 | tzinfo = TimeMixIn.FixedOffset(minutes, '?') 96 | 97 | else: 98 | tzinfo = None 99 | 100 | if '.' in text or ',' in text: 101 | if '.' in text: 102 | text, _, ms = string.partition(text, '.') 103 | else: 104 | text, _, ms = string.partition(text, ',') 105 | 106 | try: 107 | ms = int(ms) * 1000 108 | 109 | except ValueError: 110 | raise error.PyAsn1Error('bad sub-second time specification %s' % self) 111 | 112 | else: 113 | ms = 0 114 | 115 | if self._optionalMinutes and len(text) - self._yearsDigits == 6: 116 | text += '0000' 117 | elif len(text) - self._yearsDigits == 8: 118 | text += '00' 119 | 120 | try: 121 | dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') 122 | 123 | except ValueError: 124 | raise error.PyAsn1Error('malformed datetime format %s' % self) 125 | 126 | return dt.replace(microsecond=ms, tzinfo=tzinfo) 127 | 128 | @classmethod 129 | def fromDateTime(cls, dt): 130 | """Create |ASN.1| object from a :py:class:`datetime.datetime` object. 131 | 132 | Parameters 133 | ---------- 134 | dt: :py:class:`datetime.datetime` object 135 | The `datetime.datetime` object to initialize the |ASN.1| object 136 | from 137 | 138 | Returns 139 | ------- 140 | : 141 | new instance of |ASN.1| value 142 | """ 143 | text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') 144 | if cls._hasSubsecond: 145 | text += '.%d' % (dt.microsecond // 1000) 146 | 147 | if dt.utcoffset(): 148 | seconds = dt.utcoffset().seconds 149 | if seconds < 0: 150 | text += '-' 151 | else: 152 | text += '+' 153 | text += '%.2d%.2d' % (seconds // 3600, seconds % 3600) 154 | else: 155 | text += 'Z' 156 | 157 | return cls(text) 158 | 159 | 160 | class GeneralizedTime(char.VisibleString, TimeMixIn): 161 | __doc__ = char.VisibleString.__doc__ 162 | 163 | #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 164 | tagSet = char.VisibleString.tagSet.tagImplicitly( 165 | tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) 166 | ) 167 | 168 | # Optimization for faster codec lookup 169 | typeId = char.VideotexString.getTypeId() 170 | 171 | _yearsDigits = 4 172 | _hasSubsecond = True 173 | _optionalMinutes = True 174 | _shortTZ = True 175 | 176 | 177 | class UTCTime(char.VisibleString, TimeMixIn): 178 | __doc__ = char.VisibleString.__doc__ 179 | 180 | #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 181 | tagSet = char.VisibleString.tagSet.tagImplicitly( 182 | tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) 183 | ) 184 | 185 | # Optimization for faster codec lookup 186 | typeId = char.VideotexString.getTypeId() 187 | 188 | _yearsDigits = 2 189 | _hasSubsecond = False 190 | _optionalMinutes = False 191 | _shortTZ = False 192 | -------------------------------------------------------------------------------- /acfun/acfun.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import json 3 | import os 4 | 5 | import requests 6 | import urllib3 7 | 8 | urllib3.disable_warnings() 9 | 10 | 11 | class AcFunCheckIn: 12 | def __init__(self, check_item: dict): 13 | self.check_item = check_item 14 | self.contentid = "27259341" 15 | 16 | @staticmethod 17 | def get_cookies(session, phone, password): 18 | url = "https://id.app.acfun.cn/rest/app/login/signin" 19 | headers = { 20 | "Host": "id.app.acfun.cn", 21 | "user-agent": "AcFun/6.39.0 (iPhone; iOS 14.3; Scale/2.00)", 22 | "devicetype": "0", 23 | "accept-language": "zh-Hans-CN;q=1, en-CN;q=0.9, ja-CN;q=0.8, zh-Hant-HK;q=0.7, io-Latn-CN;q=0.6", 24 | "accept": "application/json", 25 | "content-type": "application/x-www-form-urlencoded", 26 | } 27 | data = f"password={password}&username={phone}" 28 | response = session.post(url=url, data=data, headers=headers, verify=False) 29 | acpasstoken = response.json().get("acPassToken") 30 | auth_key = str(response.json().get("auth_key")) 31 | if acpasstoken and auth_key: 32 | cookies = {"acPasstoken": acpasstoken, "auth_key": auth_key} 33 | return cookies 34 | else: 35 | return False 36 | 37 | @staticmethod 38 | def get_token(session, cookies): 39 | url = "https://id.app.acfun.cn/rest/web/token/get" 40 | headers = { 41 | "Content-Type": "application/x-www-form-urlencoded", 42 | } 43 | response = session.post(url=url, cookies=cookies, data="sid=acfun.midground.api", headers=headers, verify=False) 44 | return response.json().get("acfun.midground.api_st") 45 | 46 | def get_video(self, session): 47 | url = "https://api-ipv6.acfunchina.com/rest/app/rank/channel" 48 | data = "channelId=0&rankPeriod=DAY" 49 | headers = { 50 | "Content-Type": "application/x-www-form-urlencoded", 51 | } 52 | response = session.post(url=url, data=data, headers=headers, verify=False) 53 | self.contentid = response.json().get("rankList")[0].get("contentId") 54 | return self.contentid 55 | 56 | @staticmethod 57 | def sign(session, cookies): 58 | headers = {"acPlatform": "IPHONE"} 59 | response = session.post( 60 | url="https://api-ipv6.acfunchina.com/rest/app/user/signIn", headers=headers, cookies=cookies, verify=False 61 | ) 62 | return response.json().get("msg") 63 | 64 | @staticmethod 65 | def danmu(session, cookies): 66 | url = "https://api-ipv6.acfunchina.com/rest/app/new-danmaku/add" 67 | body = "body=sitoi&color=16777215&id=27259341&mode=1&position=5019&size=25&subChannelId=84&subChannelName=%E4%B8%BB%E6%9C%BA%E5%8D%95%E6%9C%BA&type=douga&videoId=22898696" 68 | headers = { 69 | "Content-Type": "application/x-www-form-urlencoded", 70 | } 71 | response = session.post(url=url, headers=headers, cookies=cookies, data=body, verify=False) 72 | if response.json().get("result") == 0: 73 | msg = "弹幕成功" 74 | else: 75 | msg = "弹幕失败" 76 | return msg 77 | 78 | def throwbanana(self, session, cookies): 79 | url = "https://api-ipv6.acfunchina.com/rest/app/banana/throwBanana" 80 | body = f"count=1&resourceId={self.contentid}&resourceType=2" 81 | headers = { 82 | "Content-Type": "application/x-www-form-urlencoded", 83 | } 84 | response = session.post(url=url, headers=headers, cookies=cookies, data=body, verify=False) 85 | if response.json().get("result") == 0: 86 | msg = "香蕉成功" 87 | else: 88 | msg = "香蕉失败" 89 | return msg 90 | 91 | def like(self, session, token): 92 | like_url = "https://api.kuaishouzt.com/rest/zt/interact/add" 93 | unlike_url = "https://api.kuaishouzt.com/rest/zt/interact/delete" 94 | headers = { 95 | "Content-Type": "application/x-www-form-urlencoded", 96 | } 97 | cookies = {"acfun.midground.api_st": token, "kpn": "ACFUN_APP"} 98 | body = f"interactType=1&objectId={self.contentid}&objectType=2&subBiz=mainApp" 99 | response = session.post(url=like_url, headers=headers, cookies=cookies, data=body, verify=False) 100 | session.post(url=unlike_url, headers=headers, cookies=cookies, data=body, verify=False) 101 | if response.json().get("result") == 1: 102 | msg = "点赞成功" 103 | else: 104 | msg = "点赞失败" 105 | return msg 106 | 107 | def share(self, session, cookies): 108 | url = "https://api-ipv6.acfunchina.com/rest/app/task/reportTaskAction?taskType=1&market=tencent&product=ACFUN_APP&appMode=0" 109 | headers = { 110 | "Content-Type": "application/x-www-form-urlencoded", 111 | } 112 | response = session.get(url=url, headers=headers, cookies=cookies, verify=False) 113 | if response.json().get("result") == 0: 114 | msg = "分享成功" 115 | else: 116 | msg = "分享失败" 117 | return msg 118 | 119 | def main(self): 120 | phone = self.check_item.get("acfun_phone") 121 | password = self.check_item.get("acfun_password") 122 | session = requests.session() 123 | self.get_video(session=session) 124 | cookies = self.get_cookies(session=session, phone=phone, password=password) 125 | token = self.get_token(session=session, cookies=cookies) 126 | sign_msg = self.sign(session=session, cookies=cookies) 127 | like_msg = self.like(session=session, token=token) 128 | share_msg = self.share(session=session, cookies=cookies) 129 | danmu_msg = self.danmu(session=session, cookies=cookies) 130 | throwbanana_msg = self.throwbanana(session=session, cookies=cookies) 131 | msg = ( 132 | f"帐号信息: {phone}\n签到状态: {sign_msg}\n点赞任务: {like_msg}\n" 133 | f"弹幕任务: {danmu_msg}\n香蕉任务: {throwbanana_msg}\n分享任务: {share_msg}" 134 | ) 135 | return msg 136 | 137 | 138 | if __name__ == "__main__": 139 | with open( 140 | os.path.join(os.path.dirname(os.path.dirname(__file__)), "config/config.json"), "r", encoding="utf-8" 141 | ) as f: 142 | datas = json.loads(f.read()) 143 | _check_item = datas.get("ACFUN_ACCOUNT_LIST", [])[0] 144 | print(AcFunCheckIn(check_item=_check_item).main()) 145 | --------------------------------------------------------------------------------