├── .github └── workflows │ └── start.yml ├── .gitignore ├── README.md ├── package.json ├── sdk ├── CloudClient.js ├── const.js ├── index.js ├── log.js ├── store │ ├── file-token-store.js │ ├── index.js │ ├── memstore.js │ └── store.js ├── types.js └── util.js └── src ├── Cloud189.js ├── logger.js └── push.js /.github/workflows/start.yml: -------------------------------------------------------------------------------- 1 | name: Action 2 | 3 | on: 4 | schedule: 5 | - cron: 20 16 * * * 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: 更改交换空间并link构建空间 14 | uses: zhlhlf/maximize-build-space@master 15 | with: 16 | swap-size-mb: 8192 17 | 18 | - name: 获取本仓库源码 19 | uses: actions/checkout@main 20 | 21 | - name: Cache Cookies 22 | id: cache-primes 23 | uses: actions/cache@v4 24 | with: 25 | path: .token 26 | key: sign-by_zhlhlf 27 | 28 | - name: 安装node.js环境 29 | uses: actions/setup-node@main 30 | with: 31 | node-version: 18 32 | 33 | - name: 注入私有Secrets到环境 34 | uses: zhlhlf/Secrets_To_Env@master 35 | with: 36 | secrets_json: ${{ toJSON(secrets) }} 37 | 38 | - name: 执行 39 | run: | 40 | npm install >/dev/null 2>&1 41 | npm start 42 | 43 | - name: Delete old workflow run 44 | uses: Mattraks/delete-workflow-runs@main 45 | with: 46 | token: ${{ github.token }} 47 | repository: ${{ github.repository }} 48 | retain_days: 0 49 | keep_minimum_runs: 2 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | package-lock.json 4 | 5 | .env 6 | .token 7 | 8 | tyys_cookies.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 📝 **天翼云盘签到脚本** 🤖✨ 2 | 3 | --- 4 | 5 | ### 🔑 账号配置 & 环境变量 6 | 7 | **路径**:`Settings` → `Secrets and variables` → `Actions` → `Repository secrets` 8 | 需新建以下加密变量: 9 | 10 | 11 | | 变量名 🐈 | 说明 📌 | 示例 🖼️ | 12 | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | 13 | | `TYYS` | 账号密码组,格式:`账号1 密码1 账号2 密码2`     | `u1 p1 u2 p2 ` | 14 | | `WX_PUSHER_UID` | 推送 UID(微信扫码-我的-我的 UID)[二维码](https://wxpusher.zjiecode.com/api/qrcode/4Ix7noqD3L7DMBoSlvig3t4hqjFWzPkdHqAYsg8IzkPreW7d8uGUHi9LJO4EcyJg.jpg) | `UID_123` | 15 | 16 | --- 17 | 18 | `家庭云ID抓取教程:`[Ailst 文档](https://alist.nn.ci/zh/guide/drivers/189.html#%E5%AE%B6%E5%BA%AD%E8%BD%AC%E7%A7%BB) 19 | 20 | ### 🚀 快速执行指南 21 | 22 | 1️⃣ **启用 Workflow** 23 | ✅ 点击仓库顶部 `Actions` → **`I understand my workflows, go ahead and enable them`** 开启权限 24 | 25 | 2️⃣ **触发运行** 26 | 🌟 啊喂 你都 fork 了 给仓库点个 **Star** 啊 27 | 28 | 3️⃣ **定时任务** 29 | ⏰ 每天 **北京时间 5:00** 自动执行 30 | 31 | --- 32 | 33 | ### 💻 本地调试命令 34 | 35 | ```bash 36 | git clone https://github.com/zhlhlf/drive_checkin --depth=1 37 | 38 | cd drive_checkin && npm install 39 | 40 | #账号密码空格隔开每个账号也空格隔开 例:FID u1 p1 u2 p2 u3 p3 -- FID u1 p1 u2 p2 41 | export TYYS="" 42 | 43 | # 指定签到的家庭云ID 44 | export TYY_FAMILY_ID="" 45 | 46 | # 私有云签到线程数量 默认10 47 | export PRIVATE_THREADX="" 48 | 49 | # 个人签到是否只签主账号 true(是) false为否会签到所有号 默认false 50 | export PRIVATE_ONLY_FIRST="" 51 | 52 | #推送相关 53 | export TELEGRAM_CHAT_ID="" 54 | export TELEGRAM_BOT_TOKEN="" 55 | export WX_PUSHER_APP_TOKEN="" 56 | export WX_PUSHER_UID="" 57 | npm run start 58 | ``` 59 | 60 | --- 61 | 62 | ### 🐉 青龙面板部署 63 | 64 | ```bash 65 | 66 | # 订阅链接 67 | ql repo https://github.com/zhlhlf/drive_checkin.git "src/Cloud189.js" "" ".*" "main" "js | json" 68 | 69 | # 依赖安装 70 | chalk 71 | tough-cookie 72 | dotenv 73 | superagent 74 | log4js 75 | 76 | # 配置好上面的环境变量 77 | ``` 78 | 79 | --- 80 | 81 | 🙏 **特别鸣谢** 82 | 原项目:[wes-lin/Cloud189Checkin](https://github.com/wes-lin/Cloud189Checkin) 83 | 84 | 修改 README:[ShelbyAlan](https://github.com/ShelbyAlan)💡 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drive_checkin", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node ./src/Cloud189.js ", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "chalk": "^4.1.2", 14 | "dotenv": "^16.4.5", 15 | "drive_checkin": "file:", 16 | "got": "^11.8.6", 17 | "log4js": "^6.9.1", 18 | "superagent": "^7.1.3" 19 | }, 20 | "devDependencies": { 21 | "eslint": "^8.40.0", 22 | "eslint-config-airbnb-base": "^15.0.0", 23 | "eslint-plugin-import": "^2.27.5" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sdk/CloudClient.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { 3 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); 4 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); 5 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); 6 | }; 7 | var __importDefault = (this && this.__importDefault) || function (mod) { 8 | return (mod && mod.__esModule) ? mod : { "default": mod }; 9 | }; 10 | var _CloudAuthClient_builLoginForm, _CloudClient_instances, _CloudClient_valid, _CloudClient_getAccessTokenBySsKey; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | exports.CloudClient = exports.CloudAuthClient = void 0; 13 | const url_1 = __importDefault(require("url")); 14 | const got_1 = __importDefault(require("got")); 15 | const log_1 = require("./log"); 16 | const util_1 = require("./util"); 17 | const const_1 = require("./const"); 18 | const store_1 = require("./store"); 19 | const config = { 20 | clientId: '538135150693412', 21 | model: 'KB2000', 22 | version: '9.0.6' 23 | }; 24 | class CloudAuthClient { 25 | constructor() { 26 | _CloudAuthClient_builLoginForm.set(this, (encrypt, appConf, username, password) => { 27 | const keyData = `-----BEGIN PUBLIC KEY-----\n${encrypt.pubKey}\n-----END PUBLIC KEY-----`; 28 | const usernameEncrypt = (0, util_1.rsaEncrypt)(keyData, username); 29 | const passwordEncrypt = (0, util_1.rsaEncrypt)(keyData, password); 30 | const data = { 31 | appKey: const_1.AppID, 32 | accountType: const_1.AccountType, 33 | // mailSuffix: '@189.cn', 34 | validateCode: '', 35 | captchaToken: appConf.captchaToken, 36 | dynamicCheck: 'FALSE', 37 | clientType: '1', 38 | cb_SaveName: '3', 39 | isOauth2: false, 40 | returnUrl: const_1.ReturnURL, 41 | paramId: appConf.paramId, 42 | userName: `${encrypt.pre}${usernameEncrypt}`, 43 | password: `${encrypt.pre}${passwordEncrypt}` 44 | }; 45 | return data; 46 | }); 47 | this.request = got_1.default.extend({ 48 | headers: { 49 | 'User-Agent': const_1.UserAgent, 50 | Accept: 'application/json;charset=UTF-8' 51 | }, 52 | hooks: { 53 | afterResponse: [ 54 | async (response, retryWithMergedOptions) => { 55 | log_1.log.debug(`url: ${response.requestUrl}, response: ${response.body})}`); 56 | return response; 57 | } 58 | ] 59 | } 60 | }); 61 | } 62 | /** 63 | * 获取加密参数 64 | * @returns 65 | */ 66 | getEncrypt() { 67 | return this.request.post(`${const_1.AUTH_URL}/api/logbox/config/encryptConf.do`).json(); 68 | } 69 | async getLoginForm() { 70 | const res = await this.request 71 | .get(`${const_1.WEB_URL}/api/portal/unifyLoginForPC.action`, { 72 | searchParams: { 73 | appId: const_1.AppID, 74 | clientType: const_1.ClientType, 75 | returnURL: const_1.ReturnURL, 76 | timeStamp: Date.now() 77 | } 78 | }) 79 | .text(); 80 | if (res) { 81 | const captchaToken = res.match(`'captchaToken' value='(.+?)'`)[1]; 82 | const lt = res.match(`lt = "(.+?)"`)[1]; 83 | const paramId = res.match(`paramId = "(.+?)"`)[1]; 84 | const reqId = res.match(`reqId = "(.+?)"`)[1]; 85 | return { captchaToken, lt, paramId, reqId }; 86 | } 87 | return null; 88 | } 89 | async getSessionForPC(param) { 90 | const params = Object.assign(Object.assign({ appId: const_1.AppID }, (0, const_1.clientSuffix)()), param); 91 | const res = await this.request 92 | .post(`${const_1.API_URL}/getSessionForPC.action`, { 93 | searchParams: params 94 | }) 95 | .json(); 96 | return res; 97 | } 98 | /** 99 | * 用户名密码登录 100 | * */ 101 | async loginByPassword(username, password) { 102 | log_1.log.debug('loginByPassword...'); 103 | try { 104 | const res = await Promise.all([ 105 | //1.获取公钥 106 | this.getEncrypt(), 107 | //2.获取登录参数 108 | this.getLoginForm() 109 | ]); 110 | const encrypt = res[0].data; 111 | const appConf = res[1]; 112 | const data = __classPrivateFieldGet(this, _CloudAuthClient_builLoginForm, "f").call(this, encrypt, appConf, username, password); 113 | const loginRes = await this.request 114 | .post(`${const_1.AUTH_URL}/api/logbox/oauth2/loginSubmit.do`, { 115 | headers: { 116 | Referer: const_1.AUTH_URL, 117 | lt: appConf.lt, 118 | REQID: appConf.reqId 119 | }, 120 | form: data 121 | }) 122 | .json(); 123 | if (loginRes.result !== 0) { 124 | throw new Error(loginRes.msg); 125 | } 126 | return await this.getSessionForPC({ redirectURL: loginRes.toUrl }); 127 | } 128 | catch (e) { 129 | log_1.log.error(e); 130 | throw e; 131 | } 132 | } 133 | /** 134 | * token登录 135 | */ 136 | async loginByAccessToken(accessToken) { 137 | log_1.log.debug('loginByAccessToken...'); 138 | return await this.getSessionForPC({ accessToken }); 139 | } 140 | /** 141 | * 刷新token 142 | */ 143 | refreshToken(refreshToken) { 144 | return this.request 145 | .post(`${const_1.AUTH_URL}/api/oauth2/refreshToken.do`, { 146 | form: { 147 | clientId: const_1.AppID, 148 | refreshToken, 149 | grantType: 'refresh_token', 150 | format: 'json' 151 | } 152 | }) 153 | .json(); 154 | } 155 | } 156 | exports.CloudAuthClient = CloudAuthClient; 157 | _CloudAuthClient_builLoginForm = new WeakMap(); 158 | /** 159 | * 天翼网盘客户端 160 | * @public 161 | */ 162 | class CloudClient { 163 | constructor(_options) { 164 | _CloudClient_instances.add(this); 165 | _CloudClient_valid.set(this, (options) => { 166 | if (!options.token && (!options.username || !options.password)) { 167 | log_1.log.error('valid'); 168 | throw new Error('Please provide username and password or token !'); 169 | } 170 | }); 171 | __classPrivateFieldGet(this, _CloudClient_valid, "f").call(this, _options); 172 | this.username = _options.username; 173 | this.password = _options.password; 174 | this.tokenStore = _options.token || new store_1.MemoryStore(); 175 | this.authClient = new CloudAuthClient(); 176 | this.session = { 177 | accessToken: '', 178 | sessionKey: '' 179 | }; 180 | this.request = got_1.default.extend({ 181 | retry: { 182 | limit: 5 183 | }, 184 | headers: { 185 | 'User-Agent': const_1.UserAgent, 186 | Referer: `${const_1.WEB_URL}/web/main/` 187 | }, 188 | hooks: { 189 | beforeRequest: [ 190 | async (options) => { 191 | if (options.url.href.includes(const_1.API_URL)) { 192 | const accessToken = await this.getAccessToken(); 193 | const { query } = url_1.default.parse(options.url.toString(), true); 194 | const time = String(Date.now()); 195 | const signature = (0, util_1.getSignature)(Object.assign(Object.assign({}, (options.method === 'GET' ? query : options.json)), { Timestamp: time, AccessToken: accessToken })); 196 | options.headers['Sign-Type'] = '1'; 197 | options.headers['Signature'] = signature; 198 | options.headers['Timestamp'] = time; 199 | options.headers['Accesstoken'] = accessToken; 200 | options.headers['Accept'] = 'application/json;charset=UTF-8'; 201 | } 202 | else if (options.url.href.includes(const_1.WEB_URL)) { 203 | const urlObj = new URL(options.url); 204 | if (options.url.href.includes('/open')) { 205 | const time = String(Date.now()); 206 | const appkey = '600100422'; 207 | const signature = (0, util_1.getSignature)(Object.assign(Object.assign({}, (options.method === 'GET' ? urlObj.searchParams : options.json)), { Timestamp: time, AppKey: appkey })); 208 | options.headers['Sign-Type'] = '1'; 209 | options.headers['Signature'] = signature; 210 | options.headers['Timestamp'] = time; 211 | options.headers['AppKey'] = appkey; 212 | } 213 | const sessionKey = await this.getSessionKey(); 214 | urlObj.searchParams.set('sessionKey', sessionKey); 215 | options.url = urlObj; 216 | } 217 | } 218 | ], 219 | afterResponse: [ 220 | async (response, retryWithMergedOptions) => { 221 | log_1.log.debug(`url: ${response.requestUrl}, response: ${response.body}`); 222 | if (response.statusCode === 400) { 223 | const { errorCode, errorMsg } = JSON.parse(response.body.toString()); 224 | if (errorCode === 'InvalidAccessToken') { 225 | log_1.log.debug('InvalidAccessToken retry...'); 226 | log_1.log.debug('Refresh AccessToken'); 227 | this.session.accessToken = ''; 228 | return retryWithMergedOptions({}); 229 | } 230 | else if (errorCode === 'InvalidSessionKey') { 231 | log_1.log.debug('InvalidSessionKey retry...'); 232 | log_1.log.debug('Refresh InvalidSessionKey'); 233 | this.session.sessionKey = ''; 234 | return retryWithMergedOptions({}); 235 | } 236 | } 237 | return response; 238 | } 239 | ] 240 | } 241 | }); 242 | } 243 | async getSession() { 244 | const accessToken = await this.tokenStore.getAccessToken(); 245 | if (accessToken) { 246 | try { 247 | return await this.authClient.loginByAccessToken(accessToken); 248 | } 249 | catch (e) { 250 | log_1.log.error(e); 251 | } 252 | } 253 | const refreshToken = await this.tokenStore.getRefreshToken(); 254 | if (refreshToken) { 255 | try { 256 | const refreshTokenSession = await this.authClient.refreshToken(refreshToken); 257 | await this.tokenStore.updateAccessToken(refreshTokenSession.accessToken); 258 | return await this.authClient.loginByAccessToken(refreshTokenSession.accessToken); 259 | } 260 | catch (e) { 261 | log_1.log.error(e); 262 | } 263 | } 264 | if (this.username && this.password) { 265 | try { 266 | const loginToken = await this.authClient.loginByPassword(this.username, this.password); 267 | await this.tokenStore.update({ 268 | accessToken: loginToken.accessToken, 269 | refreshToken: loginToken.refreshToken 270 | }); 271 | return loginToken; 272 | } 273 | catch (e) { 274 | log_1.log.error(e); 275 | } 276 | } 277 | throw new Error('Can not get session.'); 278 | } 279 | async getSessionKey() { 280 | if (!this.session.sessionKey) { 281 | this.session.sessionKey = (await this.getSession()).sessionKey; 282 | } 283 | return this.session.sessionKey; 284 | } 285 | /** 286 | * 获取 accessToken 287 | * @returns accessToken 288 | */ 289 | async getAccessToken() { 290 | if (!this.session.accessToken) { 291 | this.session.accessToken = (await __classPrivateFieldGet(this, _CloudClient_instances, "m", _CloudClient_getAccessTokenBySsKey).call(this)).accessToken; 292 | } 293 | return this.session.accessToken; 294 | } 295 | /** 296 | * 获取用户网盘存储容量信息 297 | * @returns 账号容量结果 298 | */ 299 | getUserSizeInfo() { 300 | return this.request 301 | .get(`${const_1.WEB_URL}/api/portal/getUserSizeInfo.action`, { 302 | headers: { Accept: 'application/json;charset=UTF-8' } 303 | }) 304 | .json(); 305 | } 306 | /** 307 | * 个人签到任务 308 | * @returns 签到结果 309 | */ 310 | userSign() { 311 | return this.request 312 | .get(`${const_1.WEB_URL}/mkt/userSign.action?rand=${new Date().getTime()}&clientType=TELEANDROID&version=${config.version}&model=${config.model}`) 313 | .json(); 314 | } 315 | /** 316 | * 获取家庭信息 317 | * @returns 家庭列表信息 318 | */ 319 | getFamilyList() { 320 | return this.request.get(`${const_1.API_URL}/open/family/manage/getFamilyList.action`).json(); 321 | } 322 | /** 323 | * 家庭签到任务 324 | * @param familyId - 家庭id 325 | * @returns 签到结果 326 | */ 327 | familyUserSign(familyId) { 328 | return this.request 329 | .get(`${const_1.API_URL}/open/family/manage/exeFamilyUserSign.action?familyId=${familyId}`) 330 | .json(); 331 | } 332 | } 333 | exports.CloudClient = CloudClient; 334 | _CloudClient_valid = new WeakMap(), _CloudClient_instances = new WeakSet(), _CloudClient_getAccessTokenBySsKey = function _CloudClient_getAccessTokenBySsKey() { 335 | return this.request.get(`${const_1.WEB_URL}/api/open/oauth2/getAccessTokenBySsKey.action`).json(); 336 | }; 337 | -------------------------------------------------------------------------------- /sdk/const.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.clientSuffix = exports.UserAgent = exports.ReturnURL = exports.ClientType = exports.AppID = exports.AccountType = exports.API_URL = exports.AUTH_URL = exports.WEB_URL = void 0; 4 | exports.WEB_URL = 'https://cloud.189.cn'; 5 | exports.AUTH_URL = 'https://open.e.189.cn'; 6 | exports.API_URL = 'https://api.cloud.189.cn'; 7 | exports.AccountType = '02'; 8 | exports.AppID = '8025431004'; 9 | exports.ClientType = '10020'; 10 | exports.ReturnURL = 'https://m.cloud.189.cn/zhuanti/2020/loginErrorPc/index.html'; 11 | exports.UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'; 12 | const Version = '6.2', PC = 'TELEPC', ChannelID = 'web_cloud.189.cn'; 13 | const clientSuffix = () => ({ 14 | clientType: PC, 15 | version: Version, 16 | channelId: ChannelID, 17 | rand: Date.now() 18 | }); 19 | exports.clientSuffix = clientSuffix; 20 | -------------------------------------------------------------------------------- /sdk/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | exports.FileTokenStore = exports.MemoryStore = exports.Store = void 0; 18 | __exportStar(require("./CloudClient"), exports); 19 | __exportStar(require("./types"), exports); 20 | var store_1 = require("./store"); 21 | Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return store_1.Store; } }); 22 | Object.defineProperty(exports, "MemoryStore", { enumerable: true, get: function () { return store_1.MemoryStore; } }); 23 | Object.defineProperty(exports, "FileTokenStore", { enumerable: true, get: function () { return store_1.FileTokenStore; } }); 24 | -------------------------------------------------------------------------------- /sdk/log.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.log = exports.Logger = exports.PADDING = exports.debug = void 0; 7 | const chalk_1 = __importDefault(require("chalk")); 8 | let printer = null; 9 | exports.debug = process.env.CLOUD189_VERBOSE === '1'; 10 | exports.PADDING = 2; 11 | class Logger { 12 | constructor(stream) { 13 | this.stream = stream; 14 | this.messageTransformer = (it) => it; 15 | } 16 | get isDebugEnabled() { 17 | return exports.debug; 18 | } 19 | info(messageOrFields, message) { 20 | this.doLog(message, messageOrFields, 'info'); 21 | } 22 | error(messageOrFields, message) { 23 | this.doLog(message, messageOrFields, 'error'); 24 | } 25 | warn(messageOrFields, message) { 26 | this.doLog(message, messageOrFields, 'warn'); 27 | } 28 | debug(messageOrFields, message) { 29 | if (this.isDebugEnabled) { 30 | this.doLog(message, messageOrFields, 'debug'); 31 | } 32 | } 33 | doLog(message, messageOrFields, level) { 34 | if (message === undefined) { 35 | this._doLog(messageOrFields, null, level); 36 | } 37 | else { 38 | this._doLog(message, messageOrFields, level); 39 | } 40 | } 41 | _doLog(message, fields, level) { 42 | // noinspection SuspiciousInstanceOfGuard 43 | if (message instanceof Error) { 44 | message = message.stack || message.toString(); 45 | } 46 | else { 47 | message = message.toString(); 48 | } 49 | const levelIndicator = level === 'error' ? '⨯' : '•'; 50 | const color = LEVEL_TO_COLOR[level]; 51 | this.stream.write(`${' '.repeat(exports.PADDING)}${color(levelIndicator)} `); 52 | this.stream.write(Logger.createMessage(this.messageTransformer(message, level), fields, level, color, exports.PADDING + 2 /* level indicator and space */)); 53 | this.stream.write('\n'); 54 | } 55 | static createMessage(message, fields, level, color, messagePadding = 0) { 56 | if (fields == null) { 57 | return message; 58 | } 59 | const fieldPadding = ' '.repeat(Math.max(2, 16 - message.length)); 60 | let text = (level === 'error' ? color(message) : message) + fieldPadding; 61 | const fieldNames = Object.keys(fields); 62 | let counter = 0; 63 | for (const name of fieldNames) { 64 | let fieldValue = fields[name]; 65 | let valuePadding = null; 66 | // Remove unnecessary line breaks 67 | if (fieldValue != null && typeof fieldValue === 'string' && fieldValue.includes('\n')) { 68 | valuePadding = ' '.repeat(messagePadding + message.length + fieldPadding.length + 2); 69 | fieldValue = fieldValue.replace(/\n\s*\n/g, `\n${valuePadding}`); 70 | } 71 | else if (Array.isArray(fieldValue)) { 72 | fieldValue = JSON.stringify(fieldValue); 73 | } 74 | text += `${color(name)}=${fieldValue}`; 75 | if (++counter !== fieldNames.length) { 76 | if (valuePadding == null) { 77 | text += ' '; 78 | } 79 | else { 80 | text += '\n' + valuePadding; 81 | } 82 | } 83 | } 84 | return text; 85 | } 86 | log(message) { 87 | if (printer == null) { 88 | this.stream.write(`${message}\n`); 89 | } 90 | else { 91 | printer(message); 92 | } 93 | } 94 | } 95 | exports.Logger = Logger; 96 | const LEVEL_TO_COLOR = { 97 | info: chalk_1.default.blue, 98 | warn: chalk_1.default.yellow, 99 | error: chalk_1.default.red, 100 | debug: chalk_1.default.white 101 | }; 102 | exports.log = new Logger(process.stdout); 103 | -------------------------------------------------------------------------------- /sdk/store/file-token-store.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { 26 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); 27 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); 28 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); 29 | }; 30 | var _FileTokenStore_instances, _FileTokenStore_loadFromFile, _FileTokenStore_saveToFile; 31 | Object.defineProperty(exports, "__esModule", { value: true }); 32 | exports.FileTokenStore = void 0; 33 | const fs = __importStar(require("node:fs")); 34 | const promisesFs = __importStar(require("node:fs/promises")); 35 | const memstore_1 = require("./memstore"); 36 | class FileTokenStore extends memstore_1.MemoryStore { 37 | constructor(filePath) { 38 | super(); 39 | _FileTokenStore_instances.add(this); 40 | this.filePath = filePath; 41 | if (!filePath) { 42 | throw new Error('Unknown file for read/write token'); 43 | } 44 | const dataJson = __classPrivateFieldGet(this, _FileTokenStore_instances, "m", _FileTokenStore_loadFromFile).call(this, filePath); 45 | if (dataJson) { 46 | super.update(dataJson); 47 | } 48 | } 49 | updateAccessToken(accessToken) { 50 | super.updateAccessToken(accessToken); 51 | return __classPrivateFieldGet(this, _FileTokenStore_instances, "m", _FileTokenStore_saveToFile).call(this, this.filePath, this.store); 52 | } 53 | updateRefreshToken(refreshToken) { 54 | super.updateRefreshToken(refreshToken); 55 | return __classPrivateFieldGet(this, _FileTokenStore_instances, "m", _FileTokenStore_saveToFile).call(this, this.filePath, this.store); 56 | } 57 | update(token) { 58 | super.update(token); 59 | return __classPrivateFieldGet(this, _FileTokenStore_instances, "m", _FileTokenStore_saveToFile).call(this, this.filePath, this.store); 60 | } 61 | } 62 | exports.FileTokenStore = FileTokenStore; 63 | _FileTokenStore_instances = new WeakSet(), _FileTokenStore_loadFromFile = function _FileTokenStore_loadFromFile(filePath) { 64 | let data = null; 65 | if (fs.existsSync(filePath)) { 66 | data = fs.readFileSync(filePath, { 67 | encoding: 'utf-8' 68 | }); 69 | } 70 | if (data) { 71 | try { 72 | return JSON.parse(data); 73 | } 74 | catch (e) { 75 | throw new Error(`Could not parse token file ${filePath}. Please ensure it is not corrupted.`); 76 | } 77 | } 78 | return null; 79 | }, _FileTokenStore_saveToFile = function _FileTokenStore_saveToFile(filePath, data) { 80 | return promisesFs.writeFile(filePath, JSON.stringify(data), { 81 | encoding: 'utf-8' 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /sdk/store/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./store"), exports); 18 | __exportStar(require("./memstore"), exports); 19 | __exportStar(require("./file-token-store"), exports); 20 | -------------------------------------------------------------------------------- /sdk/store/memstore.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MemoryStore = void 0; 4 | const store_1 = require("./store"); 5 | class MemoryStore extends store_1.Store { 6 | constructor() { 7 | super(); 8 | this.store = { 9 | accessToken: '', 10 | refreshToken: '' 11 | }; 12 | } 13 | getAccessToken() { 14 | return Promise.resolve(this.store.accessToken); 15 | } 16 | updateAccessToken(accessToken) { 17 | this.store.accessToken = accessToken; 18 | return Promise.resolve(); 19 | } 20 | updateRefreshToken(refreshToken) { 21 | this.store.refreshToken = refreshToken; 22 | return Promise.resolve(); 23 | } 24 | getRefreshToken() { 25 | return Promise.resolve(this.store.refreshToken); 26 | } 27 | update(token) { 28 | this.store = { 29 | accessToken: token.accessToken, 30 | refreshToken: token.refreshToken 31 | }; 32 | } 33 | } 34 | exports.MemoryStore = MemoryStore; 35 | -------------------------------------------------------------------------------- /sdk/store/store.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.Store = void 0; 4 | class Store { 5 | constructor() { } 6 | getAccessToken() { 7 | throw new Error('getAccessToken is not implemented'); 8 | } 9 | getRefreshToken() { 10 | throw new Error('getRefreshToken is not implemented'); 11 | } 12 | updateRefreshToken(refreshToken) { 13 | throw new Error('updateRefreshToken is not implemented'); 14 | } 15 | updateAccessToken(accessToken) { 16 | throw new Error('updateAccessToken is not implemented'); 17 | } 18 | update(token) { 19 | throw new Error('update is not implemented'); 20 | } 21 | } 22 | exports.Store = Store; 23 | -------------------------------------------------------------------------------- /sdk/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /sdk/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.rsaEncrypt = exports.getSignature = void 0; 7 | const crypto_1 = __importDefault(require("crypto")); 8 | const sortParameter = (data) => { 9 | if (!data) { 10 | return ''; 11 | } 12 | const e = Object.entries(data).map((t) => t.join('=')); 13 | e.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)); 14 | return e.join('&'); 15 | }; 16 | const getSignature = (data) => { 17 | const parameter = sortParameter(data); 18 | return crypto_1.default.createHash('md5').update(parameter).digest('hex'); 19 | }; 20 | exports.getSignature = getSignature; 21 | const rsaEncrypt = (publicKey, origData) => { 22 | const encryptedData = crypto_1.default.publicEncrypt({ 23 | key: publicKey, 24 | padding: crypto_1.default.constants.RSA_PKCS1_PADDING 25 | }, Buffer.from(origData)); 26 | return encryptedData.toString('hex').toUpperCase(); 27 | }; 28 | exports.rsaEncrypt = rsaEncrypt; 29 | -------------------------------------------------------------------------------- /src/Cloud189.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const recording = require("log4js/lib/appenders/recording"); 3 | const { CloudClient, FileTokenStore } = require("../sdk/index"); 4 | let { push } = require("./push"); 5 | 6 | const { logger } = require("./logger"); 7 | 8 | const sleep = async (ms) => { 9 | return new Promise((resolve) => setTimeout(resolve, ms)); 10 | }; 11 | 12 | const mask = (s, start, end) => { 13 | if (s == null) process.exit(0); 14 | return s.split("").fill("*", start, end).join(""); 15 | }; 16 | 17 | let timeout = 10000; 18 | 19 | const doTask = async (cloudClient) => { 20 | let result = []; 21 | let signPromises1 = []; 22 | let getSpace = [`${firstSpace}签到个人云获得(M)`]; 23 | 24 | for (let m = 0; m < process.env.PRIVATE_THREADX; m++) { 25 | signPromises1.push( 26 | (async () => { 27 | try { 28 | const res1 = await cloudClient.userSign(); 29 | if (!res1.isSign && res1.netdiskBonus) { 30 | getSpace.push(` ${res1.netdiskBonus}`); 31 | } 32 | } catch (e) {} 33 | })() 34 | ); 35 | } 36 | //超时中断 37 | await Promise.race([Promise.all(signPromises1), sleep(timeout)]); 38 | if (getSpace.length == 1) getSpace.push(" 0"); 39 | result.push(getSpace.join("")); 40 | 41 | signPromises1 = []; 42 | getSpace = [`${firstSpace}获得(M)`]; 43 | const { familyInfoResp } = await cloudClient.getFamilyList(); 44 | if (familyInfoResp) { 45 | const family = familyInfoResp.find((f) => f.familyId == FAMILY_ID); 46 | if (!family) return result; 47 | result.push(`${firstSpace}开始签到家庭云 ID: ${family.familyId}`); 48 | for (let i = 0; i < 1; i++) { 49 | signPromises1.push( 50 | (async () => { 51 | try { 52 | const res = await cloudClient.familyUserSign(family.familyId); 53 | if (!res.signStatus) { 54 | getSpace.push(` ${res.bonusSpace}`); 55 | } 56 | } catch (e) {} 57 | })() 58 | ); 59 | } 60 | //超时中断 61 | await Promise.race([Promise.all(signPromises1), sleep(timeout)]); 62 | 63 | if (getSpace.length == 1) getSpace.push(" 0"); 64 | result.push(getSpace.join("")); 65 | } 66 | return result; 67 | }; 68 | 69 | let firstSpace = " "; 70 | 71 | if (process.env.TYYS == null || process.env.TYYS == "") { 72 | logger.error("没有设置TYYS环境变量"); 73 | process.exit(0); 74 | } 75 | 76 | let FAMILY_ID; 77 | 78 | let i; 79 | 80 | let cloudClientMap = new Map(); 81 | let cloudClient = null; 82 | let userNameInfo; 83 | 84 | const fs = require("fs"); 85 | const path = require("path"); 86 | 87 | function ensureDirectoryExists(dirPath) { 88 | if (!fs.existsSync(dirPath)) { 89 | fs.mkdirSync(dirPath, { recursive: true }); 90 | } 91 | } 92 | 93 | // 使用示例 94 | const folderPath = path.join(process.cwd(), ".token"); 95 | ensureDirectoryExists(folderPath); 96 | 97 | const main = async () => { 98 | let accounts = process.env.TYYS.trim().split(/[\n ]+/); 99 | 100 | for (i = 0; i < accounts.length; i += 2) { 101 | const [userName, password] = accounts.slice(i, i + 2); 102 | 103 | userNameInfo = mask(userName, 3, 7); 104 | let token = new FileTokenStore(`.token/${userName}.json`); 105 | try { 106 | await sleep(100); 107 | cloudClient = new CloudClient({ 108 | username: userName, 109 | password, 110 | token: token, 111 | }); 112 | } catch (e) { 113 | console.error("操作失败:", e.message); // 只记录错误消息 114 | } 115 | 116 | cloudClientMap.set(userName, cloudClient); 117 | try { 118 | logger.log(`${i / 2 + 1}.账户 ${userNameInfo} 开始执行`); 119 | 120 | let { 121 | cloudCapacityInfo: cloudCapacityInfo0, 122 | familyCapacityInfo: familyCapacityInfo0, 123 | } = await cloudClient.getUserSizeInfo(); 124 | 125 | const result = await doTask(cloudClient); 126 | result.forEach((r) => logger.log(r)); 127 | 128 | let { 129 | cloudCapacityInfo: cloudCapacityInfo2, 130 | familyCapacityInfo: familyCapacityInfo2, 131 | } = await cloudClient.getUserSizeInfo(); 132 | 133 | logger.log( 134 | `${firstSpace}实际:个人容量+ ${ 135 | (cloudCapacityInfo2.totalSize - cloudCapacityInfo0.totalSize) / 136 | 1024 / 137 | 1024 138 | }M, 家庭容量+ ${ 139 | (familyCapacityInfo2.totalSize - familyCapacityInfo0.totalSize) / 140 | 1024 / 141 | 1024 142 | }M` 143 | ); 144 | logger.log( 145 | `${firstSpace}个人总容量:${( 146 | cloudCapacityInfo2.totalSize / 147 | 1024 / 148 | 1024 / 149 | 1024 150 | ).toFixed(2)}G, 家庭总容量:${( 151 | familyCapacityInfo2.totalSize / 152 | 1024 / 153 | 1024 / 154 | 1024 155 | ).toFixed(2)}G` 156 | ); 157 | } catch (e) { 158 | logger.error(e); 159 | if (e.code === "ETIMEDOUT") throw e; 160 | } finally { 161 | logger.log(""); 162 | } 163 | } 164 | }; 165 | 166 | (async () => { 167 | try { 168 | await main(); 169 | } finally { 170 | logger.log("\n\n"); 171 | const events = recording.replay(); 172 | const content = events.map((e) => `${e.data.join("")}`).join(" \n"); 173 | push("天翼云盘自动签到任务", content); 174 | } 175 | })(); 176 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | 2 | const log4js = require("log4js"); 3 | const logger = log4js.getLogger(); 4 | 5 | log4js.configure({ 6 | appenders: { 7 | vcr: { type: "recording" }, 8 | out: { 9 | type: "console", 10 | layout: { 11 | type: "pattern", 12 | pattern: "\u001b[32m%d{yyyy-MM-dd hh:mm:ss}\u001b[0m - %m", 13 | }, 14 | }, 15 | }, 16 | categories: { default: { appenders: ["vcr", "out"], level: "info" } }, 17 | }); 18 | 19 | exports.logger = logger -------------------------------------------------------------------------------- /src/push.js: -------------------------------------------------------------------------------- 1 | const superagent = require("superagent"); 2 | const { logger } = require("./logger"); 3 | 4 | let WX_PUSHER_UID = process.env.WX_PUSHER_UID; 5 | let WX_PUSHER_APP_TOKEN = process.env.WX_PUSHER_APP_TOKEN; 6 | 7 | let telegramBotToken = process.env.TELEGRAM_BOT_TOKEN; 8 | let telegramBotId = process.env.TELEGRAM_CHAT_ID; 9 | 10 | const pushTelegramBot = (title, desp) => { 11 | if (!(telegramBotToken && telegramBotId)) { 12 | return; 13 | } 14 | const data = { 15 | chat_id: telegramBotId, 16 | text: `${title}\n\n${desp}`, 17 | }; 18 | superagent 19 | .post(`https://api.telegram.org/bot${telegramBotToken}/sendMessage`) 20 | .type("form") 21 | .send(data) 22 | .timeout(3000) 23 | .then((res) => { 24 | if (res.body?.ok) { 25 | logger.info("TelegramBot推送成功"); 26 | } else { 27 | logger.error(`TelegramBot推送失败:${JSON.stringify(res.body)}`); 28 | } 29 | }) 30 | .catch((err) => { 31 | logger.error(`TelegramBot推送失败:${err}`); 32 | }); 33 | }; 34 | 35 | const pushWxPusher = (title, desp) => { 36 | if (!(WX_PUSHER_APP_TOKEN && WX_PUSHER_UID)) { 37 | return; 38 | } 39 | const data = { 40 | appToken: WX_PUSHER_APP_TOKEN, 41 | contentType: 1, 42 | summary: title, 43 | content: desp, 44 | uids: [WX_PUSHER_UID], 45 | }; 46 | superagent 47 | .post("https://wxpusher.zjiecode.com/api/send/message") 48 | .send(data) 49 | .timeout(3000) 50 | .end((err, res) => { 51 | if (err) { 52 | logger.error(`wxPusher推送失败:${JSON.stringify(err)}`); 53 | return; 54 | } 55 | const json = JSON.parse(res.text); 56 | if (json.data[0].code !== 1000) { 57 | logger.error(`wxPusher推送失败:${JSON.stringify(json)}`); 58 | } else { 59 | logger.info("wxPusher推送成功"); 60 | } 61 | }); 62 | }; 63 | 64 | const push = (title, desp) => { 65 | pushTelegramBot(title, desp); 66 | }; 67 | 68 | exports.push = push; 69 | --------------------------------------------------------------------------------