finki-auth 1.7.0 → 1.9.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 +35 -8
- package/dist/authentication.d.ts +5 -2
- package/dist/authentication.js +4 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils.d.ts +14 -0
- package/dist/utils.js +45 -0
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 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
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -21,16 +21,43 @@ You can add the package to your NPM project by running `npm i finki-auth`.
|
|
|
21
21
|
## Example
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
CasAuthentication,
|
|
26
|
+
Service,
|
|
27
|
+
isCookieValid,
|
|
28
|
+
isCookieHeaderValid,
|
|
29
|
+
} from "finki-auth";
|
|
25
30
|
|
|
26
|
-
const
|
|
27
|
-
|
|
31
|
+
const credentials = {
|
|
32
|
+
username: "example",
|
|
33
|
+
password: "secret_password",
|
|
34
|
+
};
|
|
28
35
|
|
|
29
|
-
const
|
|
36
|
+
const auth = new CasAuthentication(credentials);
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
await auth.authenticate(Service.COURSES);
|
|
39
|
+
|
|
40
|
+
// Get array of cookie objects
|
|
41
|
+
const cookies = await auth.getCookie(Service.COURSES);
|
|
42
|
+
|
|
43
|
+
// Get cookie header directly for sending requests
|
|
44
|
+
const cookieHeader = await auth.buildCookieHeader(Service.COURSES);
|
|
45
|
+
|
|
46
|
+
// Check if the cookie is still valid, and if not, call `authenticate` again
|
|
47
|
+
const isCookieValid = await auth.isCookieValid(Service.COURSES);
|
|
48
|
+
|
|
49
|
+
if (!isCookieValid) await auth.authenticate(Service.COURSES);
|
|
50
|
+
|
|
51
|
+
// There are also some utility functions available:
|
|
52
|
+
const isCookieValidStandalone = await isCookieValid({
|
|
53
|
+
service: Service.COURSES,
|
|
54
|
+
cookies,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const isCookieHeaderValidStandalone = await isCookieHeaderValid({
|
|
58
|
+
service: Service.COURSES,
|
|
59
|
+
cookieHeader,
|
|
60
|
+
});
|
|
34
61
|
```
|
|
35
62
|
|
|
36
63
|
## License
|
package/dist/authentication.d.ts
CHANGED
|
@@ -3,9 +3,12 @@ export declare class CasAuthentication {
|
|
|
3
3
|
private readonly password;
|
|
4
4
|
private readonly session;
|
|
5
5
|
private readonly username;
|
|
6
|
-
constructor(
|
|
6
|
+
constructor({ password, username }: {
|
|
7
|
+
password: string;
|
|
8
|
+
username: string;
|
|
9
|
+
});
|
|
7
10
|
private static readonly getFullLoginUrl;
|
|
8
|
-
authenticate: (service: Service) => Promise<void>;
|
|
11
|
+
readonly authenticate: (service: Service) => Promise<void>;
|
|
9
12
|
readonly buildCookieHeader: (service: Service) => Promise<string>;
|
|
10
13
|
readonly getCookie: (service: Service) => Promise<import("tough-cookie").Cookie[]>;
|
|
11
14
|
readonly isCookieValid: (service: Service) => Promise<boolean>;
|
package/dist/authentication.js
CHANGED
|
@@ -3,13 +3,14 @@ import { wrapper } from 'axios-cookiejar-support';
|
|
|
3
3
|
import { JSDOM } from 'jsdom';
|
|
4
4
|
import { CookieJar } from 'tough-cookie';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import { SERVICE_LOGIN_URLS,
|
|
6
|
+
import { SERVICE_LOGIN_URLS, SERVICE_URLS } from './constants.js';
|
|
7
7
|
import { Service } from './lib/Service.js';
|
|
8
|
+
import { getCookieValidity } from './utils.js';
|
|
8
9
|
export class CasAuthentication {
|
|
9
10
|
password;
|
|
10
11
|
session;
|
|
11
12
|
username;
|
|
12
|
-
constructor(
|
|
13
|
+
constructor({ password, username }) {
|
|
13
14
|
this.username = username;
|
|
14
15
|
this.password = password;
|
|
15
16
|
const cookieJar = new CookieJar();
|
|
@@ -48,24 +49,12 @@ export class CasAuthentication {
|
|
|
48
49
|
};
|
|
49
50
|
isCookieValid = async (service) => {
|
|
50
51
|
const url = SERVICE_URLS[service];
|
|
51
|
-
const userElementSelector = SERVICE_SUCCESS_SELECTORS[service];
|
|
52
52
|
const cookies = await this.getCookie(service);
|
|
53
53
|
const jar = new CookieJar();
|
|
54
54
|
for (const cookie of cookies) {
|
|
55
55
|
await jar.setCookie(cookie, url);
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
const response = await client.get(url);
|
|
59
|
-
const html = z.string().parse(response.data);
|
|
60
|
-
const { window } = new JSDOM(html);
|
|
61
|
-
const userElement = window.document.querySelector(userElementSelector);
|
|
62
|
-
switch (userElement?.textContent) {
|
|
63
|
-
case undefined:
|
|
64
|
-
case 'Најава':
|
|
65
|
-
return false;
|
|
66
|
-
default:
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
57
|
+
return await getCookieValidity({ cookieJar: jar, service });
|
|
69
58
|
};
|
|
70
59
|
getFormData = (inputs) => {
|
|
71
60
|
const urlSearchParams = new URLSearchParams();
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Cookie, CookieJar } from 'tough-cookie';
|
|
2
|
+
import type { Service } from './lib/Service.js';
|
|
3
|
+
export declare const getCookieValidity: ({ cookieJar, service, }: {
|
|
4
|
+
cookieJar: CookieJar;
|
|
5
|
+
service: Service;
|
|
6
|
+
}) => Promise<boolean>;
|
|
7
|
+
export declare const isCookieValid: ({ cookies, service, }: {
|
|
8
|
+
cookies: Cookie[];
|
|
9
|
+
service: Service;
|
|
10
|
+
}) => Promise<boolean>;
|
|
11
|
+
export declare const isCookieHeaderValid: ({ cookieHeader, service, }: {
|
|
12
|
+
cookieHeader: string;
|
|
13
|
+
service: Service;
|
|
14
|
+
}) => Promise<boolean>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { wrapper } from 'axios-cookiejar-support';
|
|
3
|
+
import { JSDOM } from 'jsdom';
|
|
4
|
+
import { CookieJar } from 'tough-cookie';
|
|
5
|
+
import z from 'zod';
|
|
6
|
+
import { SERVICE_SUCCESS_SELECTORS, SERVICE_URLS } from './constants.js';
|
|
7
|
+
export const getCookieValidity = async ({ cookieJar, service, }) => {
|
|
8
|
+
const url = SERVICE_URLS[service];
|
|
9
|
+
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) {
|
|
16
|
+
case undefined:
|
|
17
|
+
case 'Најава':
|
|
18
|
+
return false;
|
|
19
|
+
default:
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const isCookieValid = async ({ cookies, service, }) => {
|
|
24
|
+
const url = SERVICE_URLS[service];
|
|
25
|
+
const jar = new CookieJar();
|
|
26
|
+
for (const cookie of cookies) {
|
|
27
|
+
await jar.setCookie(cookie, url);
|
|
28
|
+
}
|
|
29
|
+
return getCookieValidity({ cookieJar: jar, service });
|
|
30
|
+
};
|
|
31
|
+
export const isCookieHeaderValid = async ({ cookieHeader, service, }) => {
|
|
32
|
+
const url = SERVICE_URLS[service];
|
|
33
|
+
const jar = new CookieJar();
|
|
34
|
+
const cookies = cookieHeader
|
|
35
|
+
? cookieHeader.split('; ').map((cookie) => {
|
|
36
|
+
const [key, ...valParts] = cookie.split('=');
|
|
37
|
+
const value = valParts.join('=');
|
|
38
|
+
return { key, value };
|
|
39
|
+
})
|
|
40
|
+
: [];
|
|
41
|
+
for (const { key, value } of cookies) {
|
|
42
|
+
await jar.setCookie(`${key}=${value}`, url);
|
|
43
|
+
}
|
|
44
|
+
return getCookieValidity({ cookieJar: jar, service });
|
|
45
|
+
};
|
package/package.json
CHANGED
|
@@ -13,29 +13,27 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"axios": "^1.
|
|
17
|
-
"axios-cookiejar-support": "^6.0.
|
|
18
|
-
"jsdom": "^27.
|
|
16
|
+
"axios": "^1.13.2",
|
|
17
|
+
"axios-cookiejar-support": "^6.0.5",
|
|
18
|
+
"jsdom": "^27.4.0",
|
|
19
19
|
"tough-cookie": "^6.0.0",
|
|
20
|
-
"zod": "^4.
|
|
20
|
+
"zod": "^4.3.2"
|
|
21
21
|
},
|
|
22
22
|
"description": "Authentication for FCSE services",
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@commitlint/cli": "^20.
|
|
25
|
-
"@commitlint/config-conventional": "^20.
|
|
26
|
-
"@semantic-release/changelog": "^6.0.3",
|
|
27
|
-
"@semantic-release/git": "^10.0.1",
|
|
24
|
+
"@commitlint/cli": "^20.2.0",
|
|
25
|
+
"@commitlint/config-conventional": "^20.2.0",
|
|
28
26
|
"@types/jsdom": "^27.0.0",
|
|
29
27
|
"commitizen": "^4.3.1",
|
|
30
28
|
"cz-conventional-changelog": "^3.3.0",
|
|
31
29
|
"dotenv": "^17.2.3",
|
|
32
|
-
"eslint": "^9.
|
|
33
|
-
"eslint-config-imperium": "^
|
|
30
|
+
"eslint": "^9.39.2",
|
|
31
|
+
"eslint-config-imperium": "^3.1.0",
|
|
34
32
|
"husky": "^9.1.7",
|
|
35
|
-
"rimraf": "^6.
|
|
36
|
-
"semantic-release": "^
|
|
33
|
+
"rimraf": "^6.1.2",
|
|
34
|
+
"semantic-release": "^25.0.2",
|
|
37
35
|
"typescript": "~5.9.3",
|
|
38
|
-
"vitest": "^
|
|
36
|
+
"vitest": "^4.0.16"
|
|
39
37
|
},
|
|
40
38
|
"engines": {
|
|
41
39
|
"node": "^20 || ^22 || ^24"
|
|
@@ -63,7 +61,7 @@
|
|
|
63
61
|
"commit": "cz",
|
|
64
62
|
"commitlint": "commitlint --edit",
|
|
65
63
|
"format": "eslint --ignore-pattern \"**/test/*\" --fix .",
|
|
66
|
-
"lint": "eslint . --ignore-pattern \"**/test/*\" --no-warn-ignored --cache",
|
|
64
|
+
"lint": "tsc --noEmit && eslint . --ignore-pattern \"**/test/*\" --no-warn-ignored --cache",
|
|
67
65
|
"prepare": "husky",
|
|
68
66
|
"package": "npm run build && npm pack",
|
|
69
67
|
"release": "npm run build && semantic-release",
|
|
@@ -72,5 +70,5 @@
|
|
|
72
70
|
},
|
|
73
71
|
"type": "module",
|
|
74
72
|
"types": "dist/index.d.ts",
|
|
75
|
-
"version": "1.
|
|
73
|
+
"version": "1.9.0"
|
|
76
74
|
}
|