finki-auth 1.8.0 → 2.0.0
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 +2 -1
- package/dist/authentication.js +20 -27
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/utils.js +9 -10
- package/package.json +13 -17
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# FINKI Auth
|
|
1
|
+
# FINKI Hub / FINKI Auth
|
|
2
2
|
|
|
3
3
|
Node.js package for managing authentication and cookies for FCSE's services, built using [axios](https://github.com/axios/axios).
|
|
4
4
|
|
|
@@ -46,7 +46,7 @@ const cookieHeader = await auth.buildCookieHeader(Service.COURSES);
|
|
|
46
46
|
// Check if the cookie is still valid, and if not, call `authenticate` again
|
|
47
47
|
const isCookieValid = await auth.isCookieValid(Service.COURSES);
|
|
48
48
|
|
|
49
|
-
if (!isCookieValid) await auth.authenticate();
|
|
49
|
+
if (!isCookieValid) await auth.authenticate(Service.COURSES);
|
|
50
50
|
|
|
51
51
|
// There are also some utility functions available:
|
|
52
52
|
const isCookieValidStandalone = await isCookieValid({
|
package/dist/authentication.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Service } from './lib/Service.js';
|
|
2
2
|
export declare class CasAuthentication {
|
|
3
|
+
private readonly cookieJar;
|
|
4
|
+
private readonly fetchWithCookies;
|
|
3
5
|
private readonly password;
|
|
4
|
-
private readonly session;
|
|
5
6
|
private readonly username;
|
|
6
7
|
constructor({ password, username }: {
|
|
7
8
|
password: string;
|
package/dist/authentication.js
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
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_LOGIN_URLS, SERVICE_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;
|
|
9
|
+
fetchWithCookies;
|
|
10
10
|
password;
|
|
11
|
-
session;
|
|
12
11
|
username;
|
|
13
12
|
constructor({ password, username }) {
|
|
14
13
|
this.username = username;
|
|
15
14
|
this.password = password;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
jar: cookieJar,
|
|
19
|
-
validateStatus: (status) => status >= 200 && status < 400,
|
|
20
|
-
});
|
|
21
|
-
this.session = wrapper(client);
|
|
15
|
+
this.cookieJar = new CookieJar();
|
|
16
|
+
this.fetchWithCookies = makeFetchCookie(fetch, this.cookieJar);
|
|
22
17
|
}
|
|
23
18
|
static getFullLoginUrl = (service) => {
|
|
24
19
|
if (service === Service.CAS) {
|
|
@@ -28,15 +23,14 @@ export class CasAuthentication {
|
|
|
28
23
|
};
|
|
29
24
|
authenticate = async (service) => {
|
|
30
25
|
const fullUrl = CasAuthentication.getFullLoginUrl(service);
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
await this.session.post(fullUrl, urlSearchParams);
|
|
26
|
+
const initialResponse = await this.fetchWithCookies(fullUrl);
|
|
27
|
+
const html = await initialResponse.text();
|
|
28
|
+
const $ = cheerio.load(html);
|
|
29
|
+
const urlSearchParams = this.getFormData($);
|
|
30
|
+
await this.fetchWithCookies(fullUrl, {
|
|
31
|
+
body: urlSearchParams,
|
|
32
|
+
method: 'POST',
|
|
33
|
+
});
|
|
40
34
|
};
|
|
41
35
|
buildCookieHeader = async (service) => {
|
|
42
36
|
const cookies = await this.getCookie(service);
|
|
@@ -44,8 +38,7 @@ export class CasAuthentication {
|
|
|
44
38
|
};
|
|
45
39
|
getCookie = async (service) => {
|
|
46
40
|
const serviceLoginUrl = SERVICE_LOGIN_URLS[service];
|
|
47
|
-
|
|
48
|
-
return serviceCookies ?? [];
|
|
41
|
+
return await this.cookieJar.getCookies(serviceLoginUrl);
|
|
49
42
|
};
|
|
50
43
|
isCookieValid = async (service) => {
|
|
51
44
|
const url = SERVICE_URLS[service];
|
|
@@ -56,15 +49,15 @@ export class CasAuthentication {
|
|
|
56
49
|
}
|
|
57
50
|
return await getCookieValidity({ cookieJar: jar, service });
|
|
58
51
|
};
|
|
59
|
-
getFormData = (
|
|
52
|
+
getFormData = ($) => {
|
|
60
53
|
const urlSearchParams = new URLSearchParams();
|
|
61
|
-
|
|
62
|
-
const name = input.
|
|
63
|
-
const value = input.
|
|
54
|
+
$('input[type="hidden"]').each((_i, input) => {
|
|
55
|
+
const name = $(input).attr('name');
|
|
56
|
+
const value = $(input).attr('value');
|
|
64
57
|
if (name) {
|
|
65
58
|
urlSearchParams.append(name, value ?? '');
|
|
66
59
|
}
|
|
67
|
-
}
|
|
60
|
+
});
|
|
68
61
|
urlSearchParams.append('username', this.username);
|
|
69
62
|
urlSearchParams.append('password', this.password);
|
|
70
63
|
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,32 +13,28 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"jsdom": "^27.0.0",
|
|
16
|
+
"cheerio": "^1.2.0",
|
|
17
|
+
"fetch-cookie": "^3.2.0",
|
|
19
18
|
"tough-cookie": "^6.0.0",
|
|
20
|
-
"zod": "^4.
|
|
19
|
+
"zod": "^4.3.6"
|
|
21
20
|
},
|
|
22
21
|
"description": "Authentication for FCSE services",
|
|
23
22
|
"devDependencies": {
|
|
24
|
-
"@commitlint/cli": "^20.
|
|
25
|
-
"@commitlint/config-conventional": "^20.
|
|
26
|
-
"@semantic-release/changelog": "^6.0.3",
|
|
27
|
-
"@semantic-release/git": "^10.0.1",
|
|
28
|
-
"@types/jsdom": "^27.0.0",
|
|
23
|
+
"@commitlint/cli": "^20.4.2",
|
|
24
|
+
"@commitlint/config-conventional": "^20.4.2",
|
|
29
25
|
"commitizen": "^4.3.1",
|
|
30
26
|
"cz-conventional-changelog": "^3.3.0",
|
|
31
|
-
"dotenv": "^17.
|
|
32
|
-
"eslint": "^9.
|
|
33
|
-
"eslint-config-imperium": "^
|
|
27
|
+
"dotenv": "^17.3.1",
|
|
28
|
+
"eslint": "^9.39.3",
|
|
29
|
+
"eslint-config-imperium": "^3.4.0",
|
|
34
30
|
"husky": "^9.1.7",
|
|
35
|
-
"rimraf": "^6.
|
|
36
|
-
"semantic-release": "^
|
|
31
|
+
"rimraf": "^6.1.3",
|
|
32
|
+
"semantic-release": "^25.0.2",
|
|
37
33
|
"typescript": "~5.9.3",
|
|
38
|
-
"vitest": "^
|
|
34
|
+
"vitest": "^4.0.18"
|
|
39
35
|
},
|
|
40
36
|
"engines": {
|
|
41
|
-
"node": "^
|
|
37
|
+
"node": "^22 || ^24"
|
|
42
38
|
},
|
|
43
39
|
"files": [
|
|
44
40
|
"dist",
|
|
@@ -72,5 +68,5 @@
|
|
|
72
68
|
},
|
|
73
69
|
"type": "module",
|
|
74
70
|
"types": "dist/index.d.ts",
|
|
75
|
-
"version": "
|
|
71
|
+
"version": "2.0.0"
|
|
76
72
|
}
|