Skip to content

Commit

Permalink
feat(core): make auth redirect service configurable
Browse files Browse the repository at this point in the history
* BREAKING CHANGE: cookie index changed to site host
  • Loading branch information
beetcb committed May 30, 2021
1 parent 3ca8829 commit 5048969
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 43 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<img alt="cea-logo" width="100" src="./assets/logo.png">
<br>
<code>c</code>ampusphere-<code>e</code>legant-<code>a</code>uth

</p></strong>

<p align="center">
Expand Down
8 changes: 6 additions & 2 deletions core/src/compatibility/edge-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@ const schoolEdgeCases = {
宁波大学: {
formIdx: 0,
rememberMe: 'on',
cookiePath: '/',
checkCaptchaPath: '/needCaptcha.html',
getCaptchaPath: '/captcha.html',
},
武汉大学: {
formIdx: 0,
rememberMe: 'on',
checkCaptchaPath: '/needCaptcha.html',
getCaptchaPath: '/sliderCaptcha.do',
},
}

// we will using proxy to get the default properties
const defaultProps = {
rememberMe: true,
getCaptchaPath: '/getCaptcha.htl',
checkCaptchaPath: '/checkNeedCaptcha.htl',
cookiePath: '/authserver',
formIdx: 2,
pwdEncrypt: true,
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ export async function getSchoolInfos(
}
schoolInfos[abbreviation] = {
defaultAddr,
loginStartEndpoint: `${origin}/iap/login?service=${
campuseAuthStartEndpoint: `${origin}/iap/login?service=${
encodeURIComponent(
`${origin}/portal/login`,
)
}`,
swms: casOrigin,
auth: casOrigin,
chineseName: data.name,
campusphere: origin,
isIap: data.joinType !== 'NOTCLOUD',
Expand Down
22 changes: 11 additions & 11 deletions core/src/crawler/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { FetchWithCookie } from '../utils/fetch-helper'
export default async function login(
school: SchoolConfOpts,
user: UserConfOpts,
startPointFinder: string,
) {
// improve school campatibility with defaults and edge-cases
const schoolEdgeCases: DefaultProps = getEdgeCases(
Expand All @@ -41,12 +42,11 @@ export default async function login(

const fetch = new FetchWithCookie(headers)
const name = user.alias
const cookiePath = schoolEdgeCases.cookiePath

let res: Response
// get base session
res = await fetch.get(school.loginStartEndpoint)
// redirect to auth
// ensure redirection to the right auth service
res = await fetch.get(startPointFinder)
// redirect to auth, start login
res = await fetch.follow()

// grab hidden input name-value, this maybe error-prone, but compatible
Expand Down Expand Up @@ -78,7 +78,9 @@ export default async function login(
headers.Referer = res.headers.get('location')!
const ltWrapper = new URL(headers.Referer).search
if (Object.keys(hiddenInputNameValueMap).length === 0) {
res = await fetch.get(`${school.swms}${schoolEdgeCases.lt}${ltWrapper}`)
res = await fetch.get(
`${school.auth}${schoolEdgeCases.lt}${ltWrapper}`,
)
const { result } = await res.json()
Object.defineProperties(hiddenInputNameValueMap, {
lt: { value: result._lt, enumerable: true },
Expand Down Expand Up @@ -108,8 +110,7 @@ export default async function login(
? (
await (
await fetch.get(
`${school.swms}${schoolEdgeCases.checkCaptchaPath}${addtionalParams}`,
{ cookiePath },
`${school.auth}${schoolEdgeCases.checkCaptchaPath}${addtionalParams}`,
)
).text()
).includes('true')
Expand All @@ -122,7 +123,7 @@ export default async function login(
})
const captcha = (
await ocr(
`${school.swms}${schoolEdgeCases.getCaptchaPath}${addtionalParams}`,
`${school.auth}${schoolEdgeCases.getCaptchaPath}${addtionalParams}`,
)
).replace(/\s/g, '')

Expand All @@ -144,7 +145,6 @@ export default async function login(
res = await fetch.follow({
type: 'form',
body: auth.toString(),
cookiePath: cookiePath,
})

const isRedirect = res.headers.get('location')
Expand All @@ -160,10 +160,10 @@ export default async function login(
}

// redirect to campus
res = await fetch.follow({ cookiePath })
res = await fetch.follow()

// get MOD_AUTH_CAS
res = await fetch.follow({ cookiePath })
res = await fetch.follow()

if (/30(1|2|7|8)/.test(res.status + '')) {
log.success({
Expand Down
26 changes: 18 additions & 8 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,30 @@ export * from './conf'
// log utils for plugin & cli use
export { log }

export async function handleCookie() {
export async function handleCookie(startPointFinder: string) {
await Promise.all(
sstore.get('users').map(async (i: UserConfOpts) => {
const storeCookiePath = `cookie.${i.alias}`
await handleLogin(i, storeCookiePath)
await handleLogin(i, storeCookiePath, startPointFinder)
}),
)
}

async function handleLogin(i: UserConfOpts, storeCookiePath: string) {
async function handleLogin(
i: UserConfOpts,
storeCookiePath: string,
startPointFinder: string,
) {
let cookie: CookieRawObject = sstore.get(storeCookiePath)
const name = i.alias
const school = (sstore.get('schools') as SchoolConf)[i.school]
// Check if the cookie is stored, if not, login in to eat them
if (!cookie) {
const result = await login(school, i)
const result = await login(
school,
i,
startPointFinder || school.campuseAuthStartEndpoint,
)
if (result) {
sstore.set(storeCookiePath, result)
log.success({
Expand All @@ -43,11 +51,13 @@ async function handleLogin(i: UserConfOpts, storeCookiePath: string) {
})
}
} else {
// Check if the cookie is valid
const test = await fetch(school.campusphere + '/portal/login', {
const authCookieIdx = new URL(school.auth).host
// check if the cookie is valid
const test = await fetch(`${school.auth}/login`, {
headers: {
cookie: cookie['campusphere::/'],
cookie: cookie[authCookieIdx],
},
redirect: 'manual',
})
if (test.headers.get('set-cookie')) {
// invaild cookie
Expand All @@ -56,7 +66,7 @@ async function handleLogin(i: UserConfOpts, storeCookiePath: string) {
suffix: `@${name}`,
})
sstore.del(storeCookiePath)
await handleLogin(i, storeCookiePath)
await handleLogin(i, storeCookiePath, startPointFinder)
}
log.success({
message: `尝试使用缓存中的 COOKIE`,
Expand Down
5 changes: 2 additions & 3 deletions core/src/types/conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ export type SchoolConfOpts = {
// idsUrl
campusphere: string
// `${compusphere.origin}/iap/login?service=${encodeURIComponent(`${campusphere}/portal/login`)}`
loginStartEndpoint: string
campuseAuthStartEndpoint: string
chineseName: string
defaultAddr: string
// ampUrl 1 or 2
swms: string
isIap: boolean
auth: string
}
6 changes: 1 addition & 5 deletions core/src/types/cookie.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
export type CookieMap = Map<string, Map<string, string>>

export type CookieRawObject = {
[
key in
| `campusphere::${'/authserver' | '/iap' | '/'}`
| `swms::${'/authserver' | '/iap' | '/'}`
]: string
[K: string]: string
}

export interface FetchCookieOptions {
Expand Down
6 changes: 3 additions & 3 deletions core/src/utils/cookie-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function cookieParse(host: string, headers: Headers): CookieMap {
continue
}
const [key, val] = keyVal.split('=')
const mapIdx = `${host}::${path}`
const mapIdx = host
if (lastIdxMark !== mapIdx) {
if (lastIdxMark) {
map.set(lastIdxMark, kv)
Expand All @@ -42,9 +42,9 @@ export function cookieParse(host: string, headers: Headers): CookieMap {
/**
* Construct a cookie obj base on path
*/
export function cookieStr(host: string, path: string, cookieMap: CookieMap) {
export function cookieStr(host: string, cookieMap: CookieMap) {
let str = ''
const mapIdx = `${host}::${path}`
const mapIdx = host
const cookie = cookieMap.get(mapIdx)

if (cookie) {
Expand Down
16 changes: 7 additions & 9 deletions core/src/utils/fetch-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,13 @@ export class FetchWithCookie {

async fetch(url: string, options: FetchCookieOptions) {
const { host, origin } = new URL(url)
const { type, body, cookiePath } = options
const { type, body } = options
const { headers } = this

headers.origin = origin
headers.referer = origin
headers.host = host
headers.cookie = this.cookieMap
? cookieStr(host, cookiePath!, this.cookieMap)!
: ''
headers.cookie = this.cookieMap ? cookieStr(host, this.cookieMap)! : ''

headers['Content-Type'] = type === 'form'
? 'application/x-www-form-urlencoded'
Expand All @@ -70,9 +68,8 @@ export class FetchWithCookie {
getCookieObj() {
let obj: StringKV = {}
for (const [key, val] of this.cookieMap!.entries()) {
const [_, feild, path] = key.match(/(.*)(::.*)/)!
obj[`${feild.includes('campusphere') ? 'campusphere' : 'swms'}${path}`] =
[...val].reduce((str, e) => `${str}${e.join('=')}; `, '')
// ignore cookie path, lower complexity
obj[key] = [...val].reduce((str, e) => `${str}${e.join('=')}; `, '')
}
return obj
}
Expand All @@ -81,8 +78,9 @@ export class FetchWithCookie {
if (!this.cookieMap) {
this.cookieMap = newMap
} else {
for (const [path, kv] of newMap.entries()) {
this.cookieMap.set(path, kv)
for (const [key, val] of newMap.entries()) {
const oldVal = this.cookieMap.get(key)
this.cookieMap.set(key, new Map(oldVal ? [...val, ...oldVal] : val))
}
}
}
Expand Down

0 comments on commit 5048969

Please sign in to comment.