finki-auth 1.9.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 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
 
@@ -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;
@@ -1,24 +1,19 @@
1
- import axios from 'axios';
2
- import { wrapper } from 'axios-cookiejar-support';
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
- const cookieJar = new CookieJar();
17
- const client = axios.create({
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 initialRequest = await this.session.get(fullUrl);
32
- const { data } = z.string().safeParse(initialRequest.data);
33
- if (!data) {
34
- throw new Error('Failed to parse initial request data');
35
- }
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);
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
- const serviceCookies = await this.session.defaults.jar?.getCookies(serviceLoginUrl);
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 = (inputs) => {
52
+ getFormData = ($) => {
60
53
  const urlSearchParams = new URLSearchParams();
61
- for (const input of inputs) {
62
- const name = input.getAttribute('name');
63
- const value = input.getAttribute('value');
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');
@@ -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.me-2";
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.me-2',
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 axios from 'axios';
2
- import { wrapper } from 'axios-cookiejar-support';
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 client = wrapper(axios.create({ jar: cookieJar }));
11
- const response = await client.get(url);
12
- const html = z.string().parse(response.data);
13
- const { window } = new JSDOM(html);
14
- const userElement = window.document.querySelector(userElementSelector);
15
- switch (userElement?.textContent) {
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
- "axios": "^1.13.2",
17
- "axios-cookiejar-support": "^6.0.5",
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.2"
19
+ "zod": "^4.3.6"
21
20
  },
22
21
  "description": "Authentication for FCSE services",
23
22
  "devDependencies": {
24
- "@commitlint/cli": "^20.2.0",
25
- "@commitlint/config-conventional": "^20.2.0",
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.2.3",
30
- "eslint": "^9.39.2",
31
- "eslint-config-imperium": "^3.1.0",
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.2",
31
+ "rimraf": "^6.1.3",
34
32
  "semantic-release": "^25.0.2",
35
33
  "typescript": "~5.9.3",
36
- "vitest": "^4.0.16"
34
+ "vitest": "^4.0.18"
37
35
  },
38
36
  "engines": {
39
- "node": "^20 || ^22 || ^24"
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": "1.9.0"
71
+ "version": "2.0.0"
74
72
  }