finki-auth 1.9.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/authentication.d.ts +1 -1
- package/dist/authentication.js +29 -30
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/utils.js +9 -10
- package/package.json +12 -14
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# FINKI Auth
|
|
1
|
+
# FINKI Hub / FINKI Auth
|
|
2
2
|
|
|
3
|
-
Node.js package for managing authentication and cookies for FCSE's services
|
|
3
|
+
Node.js package for managing authentication and cookies for FCSE's services.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
package/dist/authentication.d.ts
CHANGED
package/dist/authentication.js
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { JSDOM } from 'jsdom';
|
|
1
|
+
import * as cheerio from 'cheerio';
|
|
2
|
+
import makeFetchCookie from 'fetch-cookie';
|
|
4
3
|
import { CookieJar } from 'tough-cookie';
|
|
5
|
-
import {
|
|
6
|
-
import { SERVICE_LOGIN_URLS, SERVICE_URLS } from './constants.js';
|
|
4
|
+
import { SERVICE_LOGIN_URLS } from './constants.js';
|
|
7
5
|
import { Service } from './lib/Service.js';
|
|
8
6
|
import { getCookieValidity } from './utils.js';
|
|
9
7
|
export class CasAuthentication {
|
|
8
|
+
cookieJar;
|
|
10
9
|
password;
|
|
11
|
-
session;
|
|
12
10
|
username;
|
|
13
11
|
constructor({ password, username }) {
|
|
14
12
|
this.username = username;
|
|
15
13
|
this.password = password;
|
|
16
|
-
|
|
17
|
-
const client = axios.create({
|
|
18
|
-
jar: cookieJar,
|
|
19
|
-
validateStatus: (status) => status >= 200 && status < 400,
|
|
20
|
-
});
|
|
21
|
-
this.session = wrapper(client);
|
|
14
|
+
this.cookieJar = new CookieJar();
|
|
22
15
|
}
|
|
23
16
|
static getFullLoginUrl = (service) => {
|
|
24
17
|
if (service === Service.CAS) {
|
|
@@ -27,16 +20,23 @@ export class CasAuthentication {
|
|
|
27
20
|
return `${SERVICE_LOGIN_URLS[Service.CAS]}?service=${encodeURIComponent(SERVICE_LOGIN_URLS[service])}`;
|
|
28
21
|
};
|
|
29
22
|
authenticate = async (service) => {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
const jar = new CookieJar();
|
|
24
|
+
const fetchWithCookies = makeFetchCookie(fetch, jar);
|
|
25
|
+
const casLoginUrl = CasAuthentication.getFullLoginUrl(service);
|
|
26
|
+
const initialResponse = await fetchWithCookies(casLoginUrl);
|
|
27
|
+
const html = await initialResponse.text();
|
|
28
|
+
const $ = cheerio.load(html);
|
|
29
|
+
const urlSearchParams = this.getFormData($);
|
|
30
|
+
const postResponse = await fetchWithCookies(casLoginUrl, {
|
|
31
|
+
body: urlSearchParams,
|
|
32
|
+
method: 'POST',
|
|
33
|
+
});
|
|
34
|
+
await postResponse.body?.cancel();
|
|
35
|
+
const serviceLoginUrl = SERVICE_LOGIN_URLS[service];
|
|
36
|
+
const serviceCookies = await jar.getCookies(serviceLoginUrl);
|
|
37
|
+
for (const cookie of serviceCookies) {
|
|
38
|
+
await this.cookieJar.setCookie(cookie, serviceLoginUrl);
|
|
35
39
|
}
|
|
36
|
-
const { window } = new JSDOM(data);
|
|
37
|
-
const hiddenInputs = window.document.querySelectorAll('input[type="hidden"]');
|
|
38
|
-
const urlSearchParams = this.getFormData(hiddenInputs);
|
|
39
|
-
await this.session.post(fullUrl, urlSearchParams);
|
|
40
40
|
};
|
|
41
41
|
buildCookieHeader = async (service) => {
|
|
42
42
|
const cookies = await this.getCookie(service);
|
|
@@ -44,27 +44,26 @@ export class CasAuthentication {
|
|
|
44
44
|
};
|
|
45
45
|
getCookie = async (service) => {
|
|
46
46
|
const serviceLoginUrl = SERVICE_LOGIN_URLS[service];
|
|
47
|
-
|
|
48
|
-
return serviceCookies ?? [];
|
|
47
|
+
return await this.cookieJar.getCookies(serviceLoginUrl);
|
|
49
48
|
};
|
|
50
49
|
isCookieValid = async (service) => {
|
|
51
|
-
const
|
|
50
|
+
const serviceLoginUrl = SERVICE_LOGIN_URLS[service];
|
|
52
51
|
const cookies = await this.getCookie(service);
|
|
53
52
|
const jar = new CookieJar();
|
|
54
53
|
for (const cookie of cookies) {
|
|
55
|
-
await jar.setCookie(cookie,
|
|
54
|
+
await jar.setCookie(cookie, serviceLoginUrl);
|
|
56
55
|
}
|
|
57
56
|
return await getCookieValidity({ cookieJar: jar, service });
|
|
58
57
|
};
|
|
59
|
-
getFormData = (
|
|
58
|
+
getFormData = ($) => {
|
|
60
59
|
const urlSearchParams = new URLSearchParams();
|
|
61
|
-
|
|
62
|
-
const name = input.
|
|
63
|
-
const value = input.
|
|
60
|
+
$('input[type="hidden"]').each((_i, input) => {
|
|
61
|
+
const name = $(input).attr('name');
|
|
62
|
+
const value = $(input).attr('value');
|
|
64
63
|
if (name) {
|
|
65
64
|
urlSearchParams.append(name, value ?? '');
|
|
66
65
|
}
|
|
67
|
-
}
|
|
66
|
+
});
|
|
68
67
|
urlSearchParams.append('username', this.username);
|
|
69
68
|
urlSearchParams.append('password', this.password);
|
|
70
69
|
urlSearchParams.append('submit', 'LOGIN');
|
package/dist/constants.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare const SERVICE_SUCCESS_SELECTORS: {
|
|
|
21
21
|
readonly consultations: "a#username";
|
|
22
22
|
readonly courses: "span.usertext.me-1";
|
|
23
23
|
readonly diplomas: "#logoutForm > ul > li:nth-child(1) > a";
|
|
24
|
-
readonly internships: "span.
|
|
24
|
+
readonly internships: "span.text-white";
|
|
25
25
|
readonly masters: "li > a > span";
|
|
26
26
|
readonly old_courses: "span.usertext.mr-1";
|
|
27
27
|
};
|
package/dist/constants.js
CHANGED
|
@@ -22,7 +22,7 @@ export const SERVICE_SUCCESS_SELECTORS = {
|
|
|
22
22
|
[Service.CONSULTATIONS]: 'a#username',
|
|
23
23
|
[Service.COURSES]: 'span.usertext.me-1',
|
|
24
24
|
[Service.DIPLOMAS]: '#logoutForm > ul > li:nth-child(1) > a',
|
|
25
|
-
[Service.INTERNSHIPS]: 'span.
|
|
25
|
+
[Service.INTERNSHIPS]: 'span.text-white',
|
|
26
26
|
[Service.MASTERS]: 'li > a > span',
|
|
27
27
|
[Service.OLD_COURSES]: 'span.usertext.mr-1',
|
|
28
28
|
};
|
package/dist/utils.js
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { JSDOM } from 'jsdom';
|
|
1
|
+
import * as cheerio from 'cheerio';
|
|
2
|
+
import makeFetchCookie from 'fetch-cookie';
|
|
4
3
|
import { CookieJar } from 'tough-cookie';
|
|
5
|
-
import z from 'zod';
|
|
6
4
|
import { SERVICE_SUCCESS_SELECTORS, SERVICE_URLS } from './constants.js';
|
|
7
5
|
export const getCookieValidity = async ({ cookieJar, service, }) => {
|
|
8
6
|
const url = SERVICE_URLS[service];
|
|
9
7
|
const userElementSelector = SERVICE_SUCCESS_SELECTORS[service];
|
|
10
|
-
const
|
|
11
|
-
const response = await
|
|
12
|
-
const html =
|
|
13
|
-
const
|
|
14
|
-
const userElement =
|
|
15
|
-
|
|
8
|
+
const fetchWithCookies = makeFetchCookie(fetch, cookieJar);
|
|
9
|
+
const response = await fetchWithCookies(url);
|
|
10
|
+
const html = await response.text();
|
|
11
|
+
const $ = cheerio.load(html);
|
|
12
|
+
const userElement = $(userElementSelector).first();
|
|
13
|
+
const textContent = userElement.length > 0 ? userElement.text() : undefined;
|
|
14
|
+
switch (textContent) {
|
|
16
15
|
case undefined:
|
|
17
16
|
case 'Најава':
|
|
18
17
|
return false;
|
package/package.json
CHANGED
|
@@ -13,30 +13,28 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"jsdom": "^27.4.0",
|
|
16
|
+
"cheerio": "^1.2.0",
|
|
17
|
+
"fetch-cookie": "^3.2.0",
|
|
19
18
|
"tough-cookie": "^6.0.0",
|
|
20
|
-
"zod": "^4.3.
|
|
19
|
+
"zod": "^4.3.6"
|
|
21
20
|
},
|
|
22
21
|
"description": "Authentication for FCSE services",
|
|
23
22
|
"devDependencies": {
|
|
24
|
-
"@commitlint/cli": "^20.2
|
|
25
|
-
"@commitlint/config-conventional": "^20.2
|
|
26
|
-
"@types/jsdom": "^27.0.0",
|
|
23
|
+
"@commitlint/cli": "^20.4.2",
|
|
24
|
+
"@commitlint/config-conventional": "^20.4.2",
|
|
27
25
|
"commitizen": "^4.3.1",
|
|
28
26
|
"cz-conventional-changelog": "^3.3.0",
|
|
29
|
-
"dotenv": "^17.
|
|
30
|
-
"eslint": "^9.39.
|
|
31
|
-
"eslint-config-imperium": "^3.
|
|
27
|
+
"dotenv": "^17.3.1",
|
|
28
|
+
"eslint": "^9.39.3",
|
|
29
|
+
"eslint-config-imperium": "^3.4.0",
|
|
32
30
|
"husky": "^9.1.7",
|
|
33
|
-
"rimraf": "^6.1.
|
|
31
|
+
"rimraf": "^6.1.3",
|
|
34
32
|
"semantic-release": "^25.0.2",
|
|
35
33
|
"typescript": "~5.9.3",
|
|
36
|
-
"vitest": "^4.0.
|
|
34
|
+
"vitest": "^4.0.18"
|
|
37
35
|
},
|
|
38
36
|
"engines": {
|
|
39
|
-
"node": "^
|
|
37
|
+
"node": "^22 || ^24"
|
|
40
38
|
},
|
|
41
39
|
"files": [
|
|
42
40
|
"dist",
|
|
@@ -70,5 +68,5 @@
|
|
|
70
68
|
},
|
|
71
69
|
"type": "module",
|
|
72
70
|
"types": "dist/index.d.ts",
|
|
73
|
-
"version": "
|
|
71
|
+
"version": "2.0.1"
|
|
74
72
|
}
|