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

Commit

Permalink
feat(school): set default addr
Browse files Browse the repository at this point in the history
  • Loading branch information
beetcb committed May 23, 2021
1 parent 6cebaf0 commit ab75eb4
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 9 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"files": [
"dist/"
],
"types": "lib/types/",
"types": "lib/src/index.d.ts",
"scripts": {
"prebuild": "rm -rf lib/",
"build": "tsc --build"
Expand Down Expand Up @@ -41,8 +41,7 @@
"enquirer": "^2.3.6",
"node-fetch": "^2.6.1",
"signale": "^1.4.0",
"tesseract.js": "^2.1.4",
"uuid": "^8.3.2"
"tesseract.js": "^2.1.4"
},
"devDependencies": {
"@types/node-fetch": "^2.5.10",
Expand Down
11 changes: 9 additions & 2 deletions plugins/check-in/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "check-in",
"name": "cea-check-in",
"version": "1.0.0",
"description": "",
"main": "index.js",
Expand All @@ -8,5 +8,12 @@
},
"keywords": [],
"author": "",
"license": "ISC"
"license": "ISC",
"dependencies": {
"node-fetch": "^2.6.1",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/uuid": "^8.3.0"
}
}
217 changes: 217 additions & 0 deletions plugins/check-in/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// import {
// CampusphereEndpoint,
// sstore,
// handleCookie,
// log,
// StringKV,
// } from '../../../src/'

import fetch from 'node-fetch'
import crypto from 'crypto'
import { v1 } from 'uuid'
/*
exports.signApp = class Checkin {
private headers: StringKV
constructor(school, user) {
this.headers = {
'user-agent':
'Mozilla/5.0 (Linux; Android 10; GM1910 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.101 Mobile Safari/537.36 cpdaily/8.2.13 wisedu/8.2.13',
'content-type': 'application/json',
}
this.addr = school.addr
this.id = user.username
// temporary store user info to reuse it, fix circular ref
process.env[user.username] = user
}
async signInfo(cookie) {
const user = process.env[this.id]
if (!cookie) {
return true
}
this.headers.cookie = cookie['campusphere::/']
const { signApi, headers } = this
const res = await fetch(signApi.list, {
method: 'POST',
headers,
body: JSON.stringify({}),
})
// TODO: handle the responsed updated cookie
if (!res.headers.get('content-type').includes('application/json')) {
return true
}
const signQ = await res.json()
const isValidCookie = signQ.message === 'SUCCESS'
if (isValidCookie) {
const data = signQ.datas
this.curTask = data.unSignedTasks[0] || data.leaveTasks[0]
return false
}
return true
}
async signWithForm() {
if (!this.curTask) {
this.result = { 签到结果: '今日签到任务已完成或COOKIE无效,取消签到' }
return
}
const { signApi, headers } = this
const {
curTask: { signInstanceWid, signWid },
} = this
let res = await fetch(signApi.detail, {
headers,
method: 'POST',
body: JSON.stringify({ signInstanceWid, signWid }),
})
const signDetails = await res.json()
let {
extraField,
longitude,
latitude,
signPlaceSelected,
isNeedExtra,
signedStuInfo,
} = signDetails.datas
const placeList = signPlaceSelected
const isSignAtHome = process.env[this.id].addr
;[longitude, latitude] = isSignAtHome
? this.signAtHomePos()
: this.locale(placeList[0])
const extraFieldItems = this.fillExtra(extraField)
const form = {
signInstanceWid,
longitude,
latitude,
isNeedExtra,
extraFieldItems,
isMalposition: isSignAtHome ? 1 : 0,
abnormalReason: '',
signPhotoUrl: '',
position: this.addr,
uaIsCpadaily: true,
signVersion: '1.0.0',
}
headers['Cpdaily-Extension'] = this.extention(form)
res = await fetch(signApi.sign, {
headers,
method: 'POST',
body: JSON.stringify(form),
})
res = await res.json()
const logInfo = {
签到结果: res.message,
签到地址: form.position,
真实信息: signedStuInfo.userName,
}
// Hide sensitive info on github actions, cause it's public by default
if (process.env.GITHUB_ACTION) {
delete logInfo['签到地址']
delete logInfo['真实信息']
}
// store result
this.result = logInfo
}
// TODO: decouple this.addr form signAtHomePos
signAtHomePos() {
const user = process.env[this.id]
// Hard coded position info
// Randomly generated from http://api.map.baidu.com/lbsapi
const userAddr = user.addr
const noRandom = userAddr instanceof Array
const posGenFromCitys = noRandom
? [userAddr]
: [
['116.622631', '40.204822', '北京市顺义区X012'],
['115.825701', '32.914915', '安徽省阜阳市颍泉区胜利北路79'],
['119.292590', '26.164789', '福建省福州市晋安区'],
['103.836093', '36.068012', '甘肃省兰州市城关区南滨河东路709'],
['108.360128', '22.883516', '广西壮族自治区南宁市兴宁区'],
['113.391549', '22.590350', '广东省中山市兴港中路172号'],
['111.292396', '30.718343', '湖北省宜昌市西陵区珍珠路32号'],
['118.793117', '32.074771', '江苏省南京市玄武区昆仑路8号'],
]
const genNum = Math.floor(Math.random() * posGenFromCitys.length)
this.addr = posGenFromCitys[genNum][2]
return this.locale({
longitude: posGenFromCitys[genNum][0] + '',
latitude: posGenFromCitys[genNum][1] + '',
})
}
// construct coordinates & format coordinates length
locale({ longitude, latitude }) {
return [longitude.slice(0, 10), latitude.slice(0, 9)].map((e) => {
if (e[e.length - 1] === '0') {
e = e.replace(/\d{1}$/, '1')
}
return Number(e)
})
}
// select right item with content&wid
fillExtra(extraField) {
return extraField.map((e) => {
let chosenWid
const normal = e.extraFieldItems.filter((i) => {
if (i.isAbnormal === false) chosenWid = i.wid
return !i.isAbnormal
})[0]
return {
extraFieldItemWid: chosenWid,
extraFieldItemValue: normal.content,
}
})
}
// construct and encrypte Cpdaily_Extension for header
extention(form) {
const Cpdaily_Extension = {
lon: form.longitude.toString(),
model: 'Cock',
appVersion: '8.2.14',
systemVersion: '4.4.4',
userId: process.env[this.id].username,
systemName: 'android',
lat: form.latitude.toString(),
deviceId: v1(),
}
return this.encrypt(Cpdaily_Extension)
}
encrypt(ce) {
const algorithm = 'des-cbc'
const key = 'b3L26XNL'
const iv = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]) // Initialization vector.
const cipher = crypto.createCipheriv(algorithm, key, iv)
let encrypted = cipher.update(JSON.stringify(ce), 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
decrypt() {
const algorithm = 'des-cbc'
const key = 'b3L26XNL'
const iv = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]) // Initialization vector.
const decipher = crypto.createDecipheriv(algorithm, key, iv)
const encrypted = 'long base 64'
let decrypted = decipher.update(encrypted, 'base64', 'utf8')
decrypted += decipher.final('utf8')
}
}
*/
1 change: 1 addition & 0 deletions src/campusphere/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CampusphereEndpoint } from '../constants'
11 changes: 11 additions & 0 deletions src/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ export async function getSchoolInfos(
users: UsersConf
): Promise<SchoolConf | null> {
let res: Response,
defaultAddr: string,
schoolInfos = {} as SchoolConf
const schoolNamesSet = new Set(users.map((e) => e.school))
const isSchoolAddrNeeded = users.find((e) => e.addr.length === 1)
for (const abbreviation of schoolNamesSet) {
res = (await fetch(
`https://mobile.campushoy.com/v6/config/guest/tenant/info?ids=${abbreviation}`
Expand All @@ -118,7 +120,16 @@ export async function getSchoolInfos(
origin = new URL(data.ampUrl2).origin
}

res = (await fetch(
`https://api.map.baidu.com/?qt=s&wd=${encodeURIComponent(
data.name
)}&ak=E4805d16520de693a3fe707cdc962045&rn=10&ie=utf-8&oue=1&fromproduct=jsapi&res=api`
).catch((err) => log.error(err))) as Response
const addrInfo = await res.json()
defaultAddr = addrInfo.content[0].addr

schoolInfos[abbreviation] = {
defaultAddr,
loginStartEndpoint: `${origin}/iap/login?service=${encodeURIComponent(
`${origin}/portal/login`
)}`,
Expand Down
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ export enum UserAction {
DELETE = '删除用户',
CANCEL = '取消',
}

export enum CampusphereEndpoint {
getStuSignInfosInOneDay = '/wec-counselor-sign-apps/stu/sign/getStuSignInfosInOneDay',
detailSignInstance = '/wec-counselor-sign-apps/stu/sign/detailSignInstance',
submitSign = '/wec-counselor-sign-apps/stu/sign/submitSign',
}
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import log from './utils/logger'
import login from './crawler/login'
import { SchoolConf, UserConfOpts } from './types/conf'

export const sstore = require('@beetcb/sstore')

export * from './types/conf'
export * from './types/cookie'
export * from './types/helper'

import { SchoolConf, UserConfOpts } from './types/conf'
export * from './campusphere/api'
export { log }

export async function handleCookie() {
await Promise.all(
Expand Down
5 changes: 3 additions & 2 deletions src/types/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ export type SchoolConf = {
export type SchoolConfOpts = {
// idsUrl
campusphere: string
// ampUrl 1 or 2
swms: string
// `${compusphere.origin}/iap/login?service=${encodeURIComponent(`${campusphere}/portal/login`)}`
loginStartEndpoint: string
chineseName: string
defaultAddr: string
// ampUrl 1 or 2
swms: string
isIap: boolean
}

0 comments on commit ab75eb4

Please sign in to comment.