-
Notifications
You must be signed in to change notification settings - Fork 2
/
utils.ts
120 lines (110 loc) · 4.13 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
export function extractBaseUrl(url: string): string {
const protocolEndIndex = url.indexOf("://") + 3;
const pathStartIndex = url.indexOf("/", protocolEndIndex);
if (pathStartIndex === -1) {
return url;
}
return url.substring(0, pathStartIndex);
}
export function convertRelativePaths(html: string, baseUrl: string) {
const attributeRegex = /(href|src)="([^"]+)"/gi;
return html.replace(attributeRegex, (match, _type, url) => {
if (!url.startsWith("http")) {
const [prefix, suffix] = match.split(url);
return prefix + baseUrl + url + suffix;
}
return match;
});
}
export function trim(str: string): string {
return str.replace(/\<(.+)\>/g, "").replace(/( )+/g, " ");
}
const firstDelimiter = `<input type="password" name="pw" id="_pw" value="" />`;
const secondDelimiter = `<input type="hidden" name="direct_div"/>`;
export interface KupidSessionAuth {
token: string;
sessionId: string;
}
export async function getToken(id: string, password: string): Promise<KupidSessionAuth> {
const {
id: idKey,
password: passwordKey,
csrf,
fake,
sessionId,
} = await (async () => {
const res = await fetch("https://portal.korea.ac.kr/front/Intro.kpd", {
headers: { referer: "https://portal.korea.ac.kr/front/Intro.kpd" },
});
if (!res.ok) throw Error("Failed to fetch kupid/intro");
const text = await res.text();
const [_, b] = text.split(firstDelimiter);
if (!b) throw Error("Failed to parse kupid/intro @ 1st delimiter");
const [c, d] = b.split(secondDelimiter);
if (!d) throw Error("Failed to parse kupid/intro @ 2nd delimiter");
const elems = c
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
if (elems.length !== 4) {
throw Error("Failed to parse kupid/intfo @ elem trimming");
}
const [idElem, passwordElem, csrfElem, fakeElem] = elems;
const idMatchArray = idElem.match(/name="(\w+)"/);
if (!idMatchArray) throw Error("Failed to parse id element");
const passwordMatchArray = passwordElem.match(/name="(\w+)"/);
if (!passwordMatchArray) throw Error("Failed to parse password element");
const csrfMatchArray = csrfElem.match(/value="(.+)"/);
if (!csrfMatchArray) throw Error("Failed to parse csrf element");
const fakeElemMatchArray = fakeElem.match(/value="(\w+)"/);
if (!fakeElemMatchArray) throw Error("Failed to parse fake element");
const [, id] = idMatchArray;
const [, password] = passwordMatchArray;
const [, csrf] = csrfMatchArray;
const [, fake] = fakeElemMatchArray;
const cookies = res.headers.getSetCookie();
if (!cookies.length) throw Error("Unexpected length of set-cookie");
const parsed = cookies.map(parseSetCookie);
const sessionId = parsed.find(({ key }) => key === "PORTAL_SESSIONID");
if (!sessionId) {
throw Error("Failed to get sessionId from set-cookie result");
}
if (!id || !password || !csrf || !fake) {
throw Error("Failed to parse elements");
}
return { id, password, csrf, fake, sessionId: sessionId.value };
})();
const token = await (async () => {
const body = new URLSearchParams({
[idKey]: id,
[passwordKey]: password,
_csrf: csrf,
[fake]: fake,
direct_div: "",
pw_pass: "",
browser: "chrome",
});
const res = await fetch("https://portal.korea.ac.kr/common/Login.kpd", {
headers: {
referer: "https://portal.korea.ac.kr/front/Intro.kpd",
cookie: `PORTAL_SESSIONID=${sessionId}`,
},
body,
method: "POST",
redirect: "manual",
});
if (res.status !== 302) throw Error("Failed to kupid/login");
const cookies = res.headers.getSetCookie();
if (!cookies.length) throw Error("Unexpected length of set-cookie");
const parsed = cookies.map(parseSetCookie);
const token = parsed.find(({ key }) => key === "ssotoken");
if (!token) throw Error("Failed to get token from set-cookie result");
return token.value;
})();
return { token, sessionId };
}
export function parseSetCookie(cookie: string) {
const [kv] = cookie.split(";");
const [key, value] = kv.split("=");
return { key, value };
}