Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

Commit

Permalink
fix(captcha): make captcha easy to config
Browse files Browse the repository at this point in the history
  • Loading branch information
beetcb committed Mar 21, 2021
1 parent 92778fd commit 63b85de
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 63 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,11 @@ cea 的登录页爬取策略比较智能(并非 `hard coded`),默认根据
// @ts-check
const schoolEdgeCases = {
+ 学校中文全称: {
+ formIdx: 2, // 默认账号密码登录表单,你需要手动查看 HTML 结构来确定
+ supportCaptcha: false, // 是否需要验证码:有些学校不需要验证码,这种情况可设为 false
+ rememberMe: 'on', // 勾选*天免登录后的值,有些学校可能是不同的字符,默认为 true,你需要手动查看登录请求来确定
+ formIdx: 2, // 默认账号密码登录表单的索引,你需要手动查看 HTML 结构来确定
+ checkCaptchaPath: '/getCaptcha.html', // 检测是否需要验证码的路径
+ getCaptchaPath: '/checkNeedCaptcha.html', // 获取验证码的路径
+ pwdEncrypt: false, // 密码是否加密,默认 true
+ rememberMe: 'on', // [这一项不会影响登录结果]勾选*天免登录后的值,有些学校可能是不同的字符,默认为 true,你需要手动查看登录请求来确定
+ },
}
```
Expand Down
31 changes: 17 additions & 14 deletions crawler/casLogIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,23 @@ module.exports = async (school, user) => {
})

// check captcha is needed
if (schoolEdgeCases.supportCaptcha) {
res = await fetch(`${school.checkCaptcha}?username=${user.username}`, {
headers,
})
if (Boolean((await res.json()).isNeed)) {
log.warning(`用户${name}: 登录需要验证码,正在用 OCR 识别`)
const captcha = (await ocr(school.getCaptcha)).replace(/\s/g, '')

if (captcha.length >= 4) {
log.warning(`用户${name}: 使用验证码 ${captcha} 登录`)
} else {
log.warning(`用户${name}: 验证码识别失败,长度${captcha.length}错误`)
return
}
const needCaptcha = (
await (
await fetch(`${school.casOrigin}${schoolEdgeCases.checkCaptchaPath}?username=${user.username}`, {
headers,
})
).text()
).includes('true')

if (needCaptcha) {
log.warning(`用户${name}: 登录需要验证码,正在用 OCR 识别`)
const captcha = (await ocr(`${school.casOrigin}${schoolEdgeCases.getCaptchaPath}`)).replace(/\s/g, '')

if (captcha.length >= 4) {
log.warning(`用户${name}: 使用验证码 ${captcha} 登录`)
} else {
log.warning(`用户${name}: 验证码识别失败,长度${captcha.length}错误`)
return
}
}

Expand Down
7 changes: 5 additions & 2 deletions crawler/school-edge-cases.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ const schoolEdgeCases = {
formIdx: 2,
},
宁波大学: {
supportCaptcha: false,
checkCaptchaPath: '/needCaptcha.html',
getCaptchaPath: '/captcha.html',
rememberMe: 'on',
},
}

// we will using proxy to get the default properties
const defaultProps = {
rememberMe: true,
checkCaptchaPath: '/checkNeedCaptcha.htl',
getCaptchaPath: '/getCaptcha.htl',
formIdx: 0,
supportCaptcha: true,
pwdEncrypt: true,
}

module.exports = (schoolName) =>
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "@beetcb/cea",
"version": "2.1.2",
"version": "2.1.3",
"description": "campusphere-elegant-auth: login to swms/campusphere at ease",
"main": "dist/index.js",
"bin": "dist/cli.js",
"files": [
"dist/"
],
"scripts": {
"pub": "parcel build src/index.js src/cli.js --target node --no-source-maps && npm publish"
"pub": "parcel build src/index.js src/cli.js --target node --no-source-maps && npm publish --access public"
},
"keywords": [
"campusphere",
Expand Down Expand Up @@ -41,4 +41,4 @@
"parcel-plugin-shebang": "1.3.2",
"prettier": "2.2.1"
}
}
}
62 changes: 21 additions & 41 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ class User {

storeUsers(loadedUsers) {
const storedUsers = conf.get('users')
const alias = storedUsers.map(e => e.alias)
const alias = storedUsers.map((e) => e.alias)
if (loadedUsers) {
loadedUsers = loadedUsers.filter(e => !alias.includes(e.alias))
loadedUsers = loadedUsers.filter((e) => !alias.includes(e.alias))
} else {
loadedUsers = []
}
Expand All @@ -54,29 +54,19 @@ class User {

loadUserFromToml(toml) {
this.storeUsers(toml.users)
console.warn(
`用户${toml.users.reduce(
(acc, user) => `${acc}${user.alias} `,
' '
)}已加载`
)
console.warn(`用户${toml.users.reduce((acc, user) => `${acc}${user.alias} `, ' ')}已加载`)
}

loadUserFromEnv({ users }) {
if (users) {
const loadedUsers = users.split('\n').map(user => {
const loadedUsers = users.split('\n').map((user) => {
const [username, password, alias] = user.split(' ')
let addr = user.split('home ')[1]
addr = addr ? addr.split(' ') : null
return { username, password, alias, addr }
})
this.storeUsers(loadedUsers)
console.warn(
`用户${loadedUsers.reduce(
(acc, user) => `${acc}${user.alias} `,
' '
)}已加载`
)
console.warn(`用户${loadedUsers.reduce((acc, user) => `${acc}${user.alias} `, ' ')}已加载`)
return loadedUsers
}
}
Expand All @@ -86,12 +76,12 @@ class User {
{
type: 'list',
name: 'type',
message: `用户编辑: ${
conf.get('school') ? ' 学校信息已成功配置' : ' 学校信息未配置'
}\n 已有用户:${conf.get('users').reduce((s, e) => {
const userInfo = e.alias
return s + ' ' + userInfo
}, '')}`,
message: `用户编辑: ${conf.get('school') ? ' 学校信息已成功配置' : ' 学校信息未配置'}\n 已有用户:${conf
.get('users')
.reduce((s, e) => {
const userInfo = e.alias
return s + ' ' + userInfo
}, '')}`,
choices: [
{
value: 1,
Expand Down Expand Up @@ -139,7 +129,7 @@ class User {

const res = await prompt(questions)

if (!conf.get('users').some(e => e.alias === res.alias)) {
if (!conf.get('users').some((e) => e.alias === res.alias)) {
const addUser = {
username: res.username,
password: res.password,
Expand Down Expand Up @@ -173,9 +163,7 @@ class User {
]

const res = await prompt(questions)
const neoUsers = conf
.get('users')
.filter((el, index) => index !== res.selection)
const neoUsers = conf.get('users').filter((el, index) => index !== res.selection)
conf.set('users', neoUsers)

log.success('🎉 成功删除用户')
Expand Down Expand Up @@ -208,8 +196,7 @@ class School {
async loadSchoolFromToml(toml) {
if (!conf.get('school')) {
const school = await this.schoolApi(toml.school)
if (toml.users.some(e => e.addr === ''))
school.addr = await this.schoolAddr(school.name)
if (toml.users.some((e) => e.addr === '')) school.addr = await this.schoolAddr(school.name)
conf.set('school', school)
log.success(`你的学校 ${school.name} 已完成设定`)
}
Expand All @@ -223,8 +210,7 @@ class School {
async loadSchoolFromEnv({ school: name }, users) {
if (!conf.get('school')) {
const school = await this.schoolApi(name)
if (users.some(e => e.addr === ''))
school.addr = await this.schoolAddr(school.name)
if (users.some((e) => e.addr === '')) school.addr = await this.schoolAddr(school.name)
conf.set('school', school)
log.success(`你的学校已完成设定`)
} else {
Expand Down Expand Up @@ -257,15 +243,13 @@ class School {
if (name.match(/\w+/)) {
abbreviation = name
} else {
res = await fetch(
`https://mobile.campushoy.com/v6/config/guest/tenant/list`
).catch(err => err)
abbreviation = (await res.json()).data.find(i => i.name === name).id
res = await fetch(`https://mobile.campushoy.com/v6/config/guest/tenant/list`).catch((err) => err)
abbreviation = (await res.json()).data.find((i) => i.name === name).id
}

res = await fetch(
`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${abbreviation}`
).catch(err => err)
res = await fetch(`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${abbreviation}`).catch(
(err) => err
)
res = await JSON.parse(await res.text())

const origin = new URL(res.data[0].ampUrl).origin
Expand All @@ -282,12 +266,8 @@ class School {
name: schoolName,
casOrigin,
origin,
login: `${casOrigin}/login?service=${encodeURIComponent(
origin
)}/portal/login`,
login: `${casOrigin}/login?service=${encodeURIComponent(origin)}/portal/login`,
campusphere: `${origin}/portal/login`,
checkCaptcha: `${casOrigin}/checkNeedCaptcha.htl`,
getCaptcha: `${casOrigin}/getCaptcha.htl`,
}
}
}
Expand Down

0 comments on commit 63b85de

Please sign in to comment.