Skip to content

Commit

Permalink
fix(core): CLOUD join type result handling
Browse files Browse the repository at this point in the history
  • Loading branch information
beetcb committed Nov 11, 2021
1 parent 0759c25 commit 0924be8
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 30 deletions.
1 change: 0 additions & 1 deletion core/src/compatibility/edge-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const defaultProps = {
const cloudDefaultProps = {
lt: '/security/lt',
rememberMe: true,
checkCaptchaPath: '/checkNeedCaptcha',
getCaptchaPath: '/generateCaptcha',
submitCaptchakey: 'captcha',
}
Expand Down
36 changes: 33 additions & 3 deletions core/src/crawler/captcha.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import fs from 'node:fs'
import { stdin, stdout } from 'node:process'
import readline from 'node:readline'

import fetch from 'node-fetch'
import * as tesseract from 'tesseract.js'
const { createWorker } = tesseract
import terminalImage from 'terminal-image'
import { createWorker } from 'tesseract.js'

import type { UserConfOpts } from '../types/conf'
import type FetchWithCookie from '../utils/fetch-helper.js'

const tessdataPath = '/tmp/eng.traineddata.gz'

Expand Down Expand Up @@ -56,4 +61,29 @@ async function ocr(captchaUrl: string) {
return text
}

export default ocr
export async function captchaHandler(
url: string,
fetch: FetchWithCookie,
mode: UserConfOpts['captcha'],
): Promise<string> {
if (mode === 'MANUAL') {
const body = await fetch.get(url).then((res) => res.buffer())
// Save image to localhost, backup plan
fs.writeFile('/tmp/captcha.jpg', body, function(err) {
if (err) console.error(err)
})

// Manually input captcha by user
console.log(await terminalImage.buffer(body))
console.log(`手动输入验证码模式,验证码图片保存至 /tmp/captcha.jpg`)
const rl = readline.createInterface({ input: stdin, output: stdout })
return await new Promise((resolve) => {
rl.question('请输入验证码: ', (an) => {
resolve(an)
rl.close()
})
})
} else {
return (await ocr(url)).replace(/\s/g, '')
}
}
28 changes: 14 additions & 14 deletions core/src/types/conf.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export type UsersConf = {
notifier?: [`${number}`, string]
users: Array<UserConfOpts>
readonly notifier?: [`${number}`, string]
readonly users: Array<UserConfOpts>
}
export type UserConfOpts = {
username: string
password: string
captcha?: 'OCR'
alias: string
school: string
readonly username: string
readonly password: string
readonly captcha?: 'MANUAL' | 'OCR'
readonly alias: string
readonly school: string
addr: Array<string>
}

Expand All @@ -17,12 +17,12 @@ export type SchoolConf = {

export type SchoolConfOpts = {
// idsUrl
campusphere: string
readonly campusphere: string
// `${compusphere.origin}/iap/login?service=${encodeURIComponent(`${campusphere}/portal/login`)}`
preAuthURL: string
authURL?: string
chineseName: string
defaultAddr: string
isCloud: boolean
auth: string
readonly preAuthURL: string
readonly authURL?: string
readonly chineseName: string
readonly defaultAddr: string
readonly isCloud: boolean
readonly auth: string
}
9 changes: 9 additions & 0 deletions core/src/types/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type UnifiedLoginResult = {
resultCode: keyof typeof UnifiedLoginResultCodeMsg
needCaptcha: boolean
}

export enum UnifiedLoginResultCodeMsg {
CAPTCHA_NOTMATCH = '验证码不匹配',
FAIL_UPNOTMATCH = '账户名或密码有误',
}
32 changes: 32 additions & 0 deletions core/src/utils/encrypt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import crypto from 'node:crypto'

export default class AES {
private pwd: string
private key: string
constructor(pwd: string, key: string) {
this.pwd = pwd
this.key = key
}

encrypt() {
const { key, pwd } = this

const rs = AES.randomString
const data = rs(64) + pwd

const algorithm = 'aes-128-cbc'
const iv = Buffer.alloc(16, 0)

const cipher = crypto.createCipheriv(algorithm, key, iv)
let en = cipher.update(data, 'utf8', 'base64')
en += cipher.final('base64')
return en
}

private static randomString(len: number) {
const str = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
return Array(len)
.fill(null)
.reduce((s = '') => (s += str.charAt(Math.floor(Math.random() * 48))), '')
}
}
8 changes: 4 additions & 4 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
首先我们需要在当前工作目录下创建名为 `conf.toml` 的配置文件,该配置文件将在加载后得到如下的数据结构:

```ts
export type UsersConf = {
type UsersConf = {
notifier?: [`${number}`, string]
users: Array<UserConfOpts>
}
export type UserConfOpts = {
type UserConfOpts = {
username: string
password: string
captcha?: 'OCR'
captcha?: 'MANUAL' | 'OCR'
alias: string
school: string
addr: Array<string>
Expand All @@ -31,7 +31,7 @@
- `username`:学校统一身份验证的账号
- `password`: 学校统一身份验证的密码
- `school`:学校简称,部分学校是英文简称,其它学校是随机字符,请使用 **[学校 ID 查询工具](https://cea.beetcb.com)** 搜索查询
- `captcha`:可选配置项,决定登录时验证码的填写方式,缺省为用户手动填写,填写值只能为 `OCR`代表使用机器识别自动填写
- `captcha`:可选配置项,决定登录时验证码的填写方式,缺省为 `OCR`可填写 `MANUAL`,代表人工手动填写(交互式)
## 配置格式及语法
Expand Down
23 changes: 15 additions & 8 deletions plugins/check-in/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,17 +237,24 @@ export class CheckIn {
export async function checkIn() {
// Get cookie
await handleCookie()
// Log in and save cookie to cea
// Grab users
const users = sstore.get('users')
// Sign in
const logs = await signIn(users)
// Log out results
console.table(logs)
if (users?.length) {
// Sign in
const logs = await signIn(users)
// Log out results
if (logs) {
console.table(logs)
}
}
}

async function signIn(users: UsersConf['users']): Promise<GlobalLogInfo> {
const logs: GlobalLogInfo = {}
async function signIn(
users: UsersConf['users'],
): Promise<GlobalLogInfo | null> {
// Sign in asynchronizedly with promise all and diff instance of signApp class

const logs: GlobalLogInfo = {}
await Promise.all(
users.map(async (i) => {
const instance: CheckIn = new CheckIn(i)
Expand All @@ -270,5 +277,5 @@ async function signIn(users: UsersConf['users']): Promise<GlobalLogInfo> {
}),
)
log.notify(`签到结果 => \n${JSON.stringify(logs, null, ' ')}`)
return logs
return Object.keys(logs).length ? logs : null
}

0 comments on commit 0924be8

Please sign in to comment.