@verisoft/security-core 18.6.0 → 18.7.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.
Files changed (85) hide show
  1. package/.eslintrc.json +48 -0
  2. package/README.md +52 -3
  3. package/jest.config.ts +21 -0
  4. package/ng-package.json +7 -0
  5. package/package.json +11 -27
  6. package/project.json +36 -0
  7. package/src/index.ts +1 -0
  8. package/src/lib/directives/has-permission.directive.ts +54 -0
  9. package/src/lib/directives/has-role.directive.ts +54 -0
  10. package/{lib/directives/index.d.ts → src/lib/directives/index.ts} +2 -2
  11. package/src/lib/guards/auth.guard.ts +55 -0
  12. package/{lib/guards/index.d.ts → src/lib/guards/index.ts} +1 -1
  13. package/{lib/index.d.ts → src/lib/index.ts} +6 -6
  14. package/{lib/models/authenticated-user.model.d.ts → src/lib/models/authenticated-user.model.ts} +8 -8
  15. package/{lib/models/config.model.d.ts → src/lib/models/config.model.ts} +9 -8
  16. package/src/lib/models/functions.spec.ts +159 -0
  17. package/src/lib/models/functions.ts +103 -0
  18. package/{lib/models/index.d.ts → src/lib/models/index.ts} +3 -3
  19. package/src/lib/provider.ts +58 -0
  20. package/src/lib/services/auth-context.service.ts +38 -0
  21. package/{lib/services/index.d.ts → src/lib/services/index.ts} +7 -7
  22. package/src/lib/services/local-storage-token-provider.ts +23 -0
  23. package/src/lib/services/local-token-provider.ts +15 -0
  24. package/src/lib/services/login.service.ts +23 -0
  25. package/src/lib/services/logout.service.ts +15 -0
  26. package/src/lib/services/security-initializer.ts +26 -0
  27. package/src/lib/services/session-token-provider.ts +15 -0
  28. package/{lib/services/token-provider.d.ts → src/lib/services/token-provider.ts} +5 -4
  29. package/src/lib/state/actions.ts +7 -0
  30. package/src/lib/state/feature.ts +10 -0
  31. package/{lib/state/index.d.ts → src/lib/state/index.ts} +4 -4
  32. package/src/lib/state/reducers.ts +11 -0
  33. package/src/lib/state/selectors.ts +9 -0
  34. package/src/lib/state/state.ts +9 -0
  35. package/src/test-setup.ts +8 -0
  36. package/tsconfig.json +28 -0
  37. package/tsconfig.lib.json +17 -0
  38. package/tsconfig.lib.prod.json +9 -0
  39. package/tsconfig.spec.json +16 -0
  40. package/esm2022/index.mjs +0 -2
  41. package/esm2022/lib/directives/has-permission.directive.mjs +0 -55
  42. package/esm2022/lib/directives/has-role.directive.mjs +0 -55
  43. package/esm2022/lib/directives/index.mjs +0 -3
  44. package/esm2022/lib/guards/auth.guard.mjs +0 -40
  45. package/esm2022/lib/guards/index.mjs +0 -2
  46. package/esm2022/lib/index.mjs +0 -7
  47. package/esm2022/lib/models/authenticated-user.model.mjs +0 -2
  48. package/esm2022/lib/models/config.model.mjs +0 -2
  49. package/esm2022/lib/models/functions.mjs +0 -70
  50. package/esm2022/lib/models/index.mjs +0 -4
  51. package/esm2022/lib/provider.mjs +0 -47
  52. package/esm2022/lib/services/auth-context.service.mjs +0 -36
  53. package/esm2022/lib/services/index.mjs +0 -8
  54. package/esm2022/lib/services/local-storage-token-provider.mjs +0 -23
  55. package/esm2022/lib/services/login.service.mjs +0 -27
  56. package/esm2022/lib/services/logout.service.mjs +0 -18
  57. package/esm2022/lib/services/security-initializer.mjs +0 -14
  58. package/esm2022/lib/services/session-token-provider.mjs +0 -17
  59. package/esm2022/lib/services/token-provider.mjs +0 -2
  60. package/esm2022/lib/state/actions.mjs +0 -3
  61. package/esm2022/lib/state/feature.mjs +0 -8
  62. package/esm2022/lib/state/index.mjs +0 -5
  63. package/esm2022/lib/state/reducers.mjs +0 -8
  64. package/esm2022/lib/state/selectors.mjs +0 -5
  65. package/esm2022/lib/state/state.mjs +0 -4
  66. package/esm2022/verisoft-security-core.mjs +0 -5
  67. package/fesm2022/verisoft-security-core.mjs +0 -382
  68. package/fesm2022/verisoft-security-core.mjs.map +0 -1
  69. package/index.d.ts +0 -1
  70. package/lib/directives/has-permission.directive.d.ts +0 -17
  71. package/lib/directives/has-role.directive.d.ts +0 -17
  72. package/lib/guards/auth.guard.d.ts +0 -13
  73. package/lib/models/functions.d.ts +0 -5
  74. package/lib/provider.d.ts +0 -14
  75. package/lib/services/auth-context.service.d.ts +0 -15
  76. package/lib/services/local-storage-token-provider.d.ts +0 -11
  77. package/lib/services/login.service.d.ts +0 -10
  78. package/lib/services/logout.service.d.ts +0 -8
  79. package/lib/services/security-initializer.d.ts +0 -5
  80. package/lib/services/session-token-provider.d.ts +0 -9
  81. package/lib/state/actions.d.ts +0 -6
  82. package/lib/state/feature.d.ts +0 -7
  83. package/lib/state/reducers.d.ts +0 -1
  84. package/lib/state/selectors.d.ts +0 -2
  85. package/lib/state/state.d.ts +0 -5
package/.eslintrc.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "extends": ["../../../../.eslintrc.base.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts"],
7
+ "extends": [
8
+ "plugin:@nx/angular",
9
+ "plugin:@angular-eslint/template/process-inline-templates"
10
+ ],
11
+ "rules": {
12
+ "@angular-eslint/directive-selector": [
13
+ "error",
14
+ {
15
+ "type": "attribute",
16
+ "prefix": "",
17
+ "style": "camelCase"
18
+ }
19
+ ],
20
+ "@angular-eslint/component-selector": [
21
+ "error",
22
+ {
23
+ "type": "element",
24
+ "prefix": "v-sec",
25
+ "style": "kebab-case"
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ {
31
+ "files": ["*.html"],
32
+ "extends": ["plugin:@nx/angular-template"],
33
+ "rules": {}
34
+ },
35
+ {
36
+ "files": ["*.json"],
37
+ "parser": "jsonc-eslint-parser",
38
+ "rules": {
39
+ "@nx/dependency-checks": [
40
+ "error",
41
+ {
42
+ "ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"]
43
+ }
44
+ ]
45
+ }
46
+ }
47
+ ]
48
+ }
package/README.md CHANGED
@@ -1,7 +1,56 @@
1
1
  # security-core
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ The `security-core` library provides authentication, authorization, and security-related utilities for the Verisoft Frontend workspace.
4
4
 
5
- ## Running unit tests
5
+ ## Features
6
6
 
7
- Run `nx test security-core` to execute the unit tests.
7
+ - Authentication and authorization helpers
8
+ - Security-related Angular services and guards
9
+ - Shared security interfaces and types
10
+
11
+ ## Installation
12
+
13
+ This package is intended for internal use within the monorepo. To use it in another library or app, add it as a dependency in your `project.json`:
14
+
15
+ ```json
16
+ "dependencies": {
17
+ "security-core": "*"
18
+ }
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Import the required modules, services, or utilities from `security-core`:
24
+
25
+ ```typescript
26
+ import { AuthService } from '@verisoft/security-core';
27
+ ```
28
+
29
+ ## Development
30
+
31
+ ### Building
32
+
33
+ Run the following command to build the library:
34
+
35
+ ```sh
36
+ nx build security-core
37
+ ```
38
+
39
+ ### Running Unit Tests
40
+
41
+ To execute the unit tests for this library:
42
+
43
+ ```sh
44
+ nx test security-core
45
+ ```
46
+
47
+ ## Contributing
48
+
49
+ 1. Fork the repository and create your branch from `master`.
50
+ 2. Make your changes and add tests if needed.
51
+ 3. Run `nx test security-core` to ensure all tests pass.
52
+ 4. Submit a pull request.
53
+
54
+ ## License
55
+
56
+ This project is licensed under the MIT License.
package/jest.config.ts ADDED
@@ -0,0 +1,21 @@
1
+ export default {
2
+ displayName: 'security-core',
3
+ preset: '../../../../jest.preset.js',
4
+ setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
5
+ coverageDirectory: '../../../../coverage/src/libs/security/core',
6
+ transform: {
7
+ '^.+\\.(ts|mjs|js|html)$': [
8
+ 'jest-preset-angular',
9
+ {
10
+ tsconfig: '<rootDir>/tsconfig.spec.json',
11
+ stringifyContentPathRegex: '\\.(html|svg)$',
12
+ },
13
+ ],
14
+ },
15
+ transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
16
+ snapshotSerializers: [
17
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
18
+ 'jest-preset-angular/build/serializers/ng-snapshot',
19
+ 'jest-preset-angular/build/serializers/html-comment',
20
+ ],
21
+ };
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../../../dist/src/libs/security/core",
4
+ "lib": {
5
+ "entryFile": "src/index.ts"
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,27 +1,11 @@
1
- {
2
- "name": "@verisoft/security-core",
3
- "version": "18.6.0",
4
- "peerDependencies": {
5
- "@angular/core": "^18.2.0",
6
- "rxjs": "~7.8.0",
7
- "@angular/router": "18.2.8",
8
- "@ngrx/store": "18.0.2"
9
- },
10
- "sideEffects": false,
11
- "module": "fesm2022/verisoft-security-core.mjs",
12
- "typings": "index.d.ts",
13
- "exports": {
14
- "./package.json": {
15
- "default": "./package.json"
16
- },
17
- ".": {
18
- "types": "./index.d.ts",
19
- "esm2022": "./esm2022/verisoft-security-core.mjs",
20
- "esm": "./esm2022/verisoft-security-core.mjs",
21
- "default": "./fesm2022/verisoft-security-core.mjs"
22
- }
23
- },
24
- "dependencies": {
25
- "tslib": "^2.3.0"
26
- }
27
- }
1
+ {
2
+ "name": "@verisoft/security-core",
3
+ "version": "18.7.0",
4
+ "peerDependencies": {
5
+ "@angular/core": "^18.2.0",
6
+ "rxjs": "~7.8.0",
7
+ "@angular/router": "18.2.8",
8
+ "@ngrx/store": "18.0.2"
9
+ },
10
+ "sideEffects": false
11
+ }
package/project.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "security-core",
3
+ "$schema": "../../../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "src/libs/security/core/src",
5
+ "prefix": "lib",
6
+ "projectType": "library",
7
+ "tags": [],
8
+ "targets": {
9
+ "build": {
10
+ "executor": "@nx/angular:package",
11
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}"],
12
+ "options": {
13
+ "project": "src/libs/security/core/ng-package.json"
14
+ },
15
+ "configurations": {
16
+ "production": {
17
+ "tsConfig": "src/libs/security/core/tsconfig.lib.prod.json"
18
+ },
19
+ "development": {
20
+ "tsConfig": "src/libs/security/core/tsconfig.lib.json"
21
+ }
22
+ },
23
+ "defaultConfiguration": "production"
24
+ },
25
+ "test": {
26
+ "executor": "@nx/jest:jest",
27
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
28
+ "options": {
29
+ "jestConfig": "src/libs/security/core/jest.config.ts"
30
+ }
31
+ },
32
+ "lint": {
33
+ "executor": "@nx/eslint:lint"
34
+ }
35
+ }
36
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib';
@@ -0,0 +1,54 @@
1
+ import {
2
+ Directive,
3
+ Input,
4
+ TemplateRef,
5
+ ViewContainerRef,
6
+ OnDestroy,
7
+ } from '@angular/core';
8
+ import { distinctUntilChanged, Subscription } from 'rxjs';
9
+ import { AuthContextService } from '../services';
10
+
11
+ @Directive({
12
+ standalone: true,
13
+ selector: '[hasPermission]',
14
+ })
15
+ export class HasPermissionDirective<T> implements OnDestroy {
16
+ private requiredPermissions: string | string[] = '';
17
+ private sub?: Subscription;
18
+
19
+ constructor(
20
+ private templateRef: TemplateRef<T>,
21
+ private viewContainer: ViewContainerRef,
22
+ private authContext: AuthContextService
23
+ ) {}
24
+
25
+ @Input()
26
+ set hasPermission(value: string | string[]) {
27
+ this.requiredPermissions = value;
28
+ this.updateView();
29
+ }
30
+
31
+ ngOnDestroy(): void {
32
+ this.unregister();
33
+ }
34
+
35
+ private unregister() {
36
+ this.sub?.unsubscribe();
37
+ }
38
+
39
+ private updateView(): void {
40
+ this.unregister();
41
+ if (this.requiredPermissions || this.requiredPermissions.length) {
42
+ this.sub = this.authContext
43
+ .hasRequiredPermission(this.requiredPermissions)
44
+ .pipe(distinctUntilChanged())
45
+ .subscribe((hasPerm) => {
46
+ if (hasPerm) {
47
+ this.viewContainer.createEmbeddedView(this.templateRef);
48
+ } else {
49
+ this.viewContainer.clear();
50
+ }
51
+ });
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,54 @@
1
+ import {
2
+ Directive,
3
+ Input,
4
+ TemplateRef,
5
+ ViewContainerRef,
6
+ OnDestroy,
7
+ } from '@angular/core';
8
+ import { distinctUntilChanged, Subscription } from 'rxjs';
9
+ import { AuthContextService } from '../services';
10
+
11
+ @Directive({
12
+ standalone: true,
13
+ selector: '[hasRole]',
14
+ })
15
+ export class HasRoleDirective<T> implements OnDestroy {
16
+ private requiredRoles: string | string[] | undefined;
17
+ private sub?: Subscription;
18
+
19
+ constructor(
20
+ private templateRef: TemplateRef<T>,
21
+ private viewContainer: ViewContainerRef,
22
+ private authContext: AuthContextService
23
+ ) {}
24
+
25
+ @Input()
26
+ set hasRole(value: string | string[]) {
27
+ this.requiredRoles = value;
28
+ this.updateView();
29
+ }
30
+
31
+ ngOnDestroy(): void {
32
+ this.unregister();
33
+ }
34
+
35
+ private unregister() {
36
+ this.sub?.unsubscribe();
37
+ }
38
+
39
+ private updateView(): void {
40
+ this.unregister();
41
+ if (this.requiredRoles || this.requiredRoles?.length) {
42
+ this.sub = this.authContext
43
+ .hasRequiredRole(this.requiredRoles)
44
+ .pipe(distinctUntilChanged())
45
+ .subscribe((hasRole) => {
46
+ if (hasRole) {
47
+ this.viewContainer.createEmbeddedView(this.templateRef);
48
+ } else {
49
+ this.viewContainer.clear();
50
+ }
51
+ });
52
+ }
53
+ }
54
+ }
@@ -1,2 +1,2 @@
1
- export * from './has-permission.directive';
2
- export * from './has-role.directive';
1
+ export * from './has-permission.directive';
2
+ export * from './has-role.directive';
@@ -0,0 +1,55 @@
1
+ import { inject, Injectable } from '@angular/core';
2
+ import {
3
+ ActivatedRouteSnapshot,
4
+ CanActivate,
5
+ CanActivateChild,
6
+ Router,
7
+ UrlTree,
8
+ } from '@angular/router';
9
+ import { map, Observable, of, switchMap } from 'rxjs';
10
+ import { SecurityConfig } from '../models';
11
+ import { hasRequiredPermission } from '../models/functions';
12
+ import { SECURITY_CONFIG } from '../provider';
13
+ import { AuthContextService } from '../services';
14
+
15
+ @Injectable({
16
+ providedIn: 'root',
17
+ })
18
+ export class AuthGuard implements CanActivate, CanActivateChild {
19
+ private config = inject<SecurityConfig>(SECURITY_CONFIG);
20
+ private router = inject(Router);
21
+ private authContext = inject(AuthContextService);
22
+
23
+ canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> {
24
+ return this.checkPermissionsAndRolesAndNavigate(route, this.config.notAuthorizedPage);
25
+ }
26
+
27
+ canActivateChild(
28
+ childRoute: ActivatedRouteSnapshot
29
+ ): Observable<boolean | UrlTree> {
30
+ return this.checkPermissionsAndRolesAndNavigate(childRoute, this.config.notAuthorizedPage);
31
+ }
32
+
33
+ private checkPermissionsAndRolesAndNavigate(
34
+ route: ActivatedRouteSnapshot,
35
+ notAuthorizedUrl: string | undefined
36
+ ): Observable<boolean | UrlTree> {
37
+ const requiredPermissions = route.data['permissions'] as | string | string[] | undefined;
38
+ const requiredRoles = route.data['roles'] as string | string[] | undefined;
39
+
40
+ return this.authContext.user$.pipe(
41
+ map(
42
+ (user) => user &&
43
+ (!requiredPermissions ||
44
+ hasRequiredPermission(user, requiredPermissions)) &&
45
+ (!requiredRoles || hasRequiredPermission(user, requiredRoles))
46
+ ),
47
+ switchMap((hasPermission) => {
48
+ if (!hasPermission && notAuthorizedUrl) {
49
+ return of(this.router.parseUrl(notAuthorizedUrl));
50
+ }
51
+ return of(!!hasPermission);
52
+ })
53
+ );
54
+ }
55
+ }
@@ -1 +1 @@
1
- export * from './auth.guard';
1
+ export * from './auth.guard';
@@ -1,6 +1,6 @@
1
- export * from './directives';
2
- export * from './guards';
3
- export * from './models';
4
- export * from './services';
5
- export * from './state';
6
- export * from './provider';
1
+ export * from './directives';
2
+ export * from './guards';
3
+ export * from './models';
4
+ export * from './services';
5
+ export * from './state';
6
+ export * from './provider';
@@ -1,8 +1,8 @@
1
- export interface AuthenticatedUser {
2
- userId?: string;
3
- userName: string;
4
- email: string;
5
- displayName?: string;
6
- roles: string[] | undefined;
7
- permissions: string[] | undefined;
8
- }
1
+ export interface AuthenticatedUser {
2
+ userId?: string;
3
+ userName: string;
4
+ email: string;
5
+ displayName?: string;
6
+ roles: string[] | undefined;
7
+ permissions: string[] | undefined;
8
+ }
@@ -1,8 +1,9 @@
1
- export interface SecurityConfig {
2
- tokenStorageKey: string;
3
- contextTokenStorageKey?: string;
4
- loginPage?: string;
5
- logoutPage?: string;
6
- notAuthorizedPage?: string;
7
- sendTokenHeader?: boolean;
8
- }
1
+
2
+ export interface SecurityConfig {
3
+ tokenStorageKey: string;
4
+ contextTokenStorageKey?: string;
5
+ loginPage?: string;
6
+ logoutPage?: string;
7
+ notAuthorizedPage?: string;
8
+ sendTokenHeader?: boolean;
9
+ }
@@ -0,0 +1,159 @@
1
+ import { AuthenticatedUser } from './authenticated-user.model';
2
+ import {
3
+ convertJWTToUser,
4
+ hasRequiredPermission,
5
+ hasRequiredRole,
6
+ } from './functions';
7
+
8
+ describe('Permissions Utils', () => {
9
+ let user: AuthenticatedUser;
10
+
11
+ beforeEach(() => {
12
+ user = {
13
+ userName: 'testUser',
14
+ email: 'test@email.cz',
15
+ displayName: 'Test User',
16
+ permissions: ['READ', 'WRITE', 'DELETE_USER'],
17
+ roles: ['ADMIN', 'USER'],
18
+ };
19
+ });
20
+
21
+ describe('hasRequiredPermission', () => {
22
+ it('should return false if user is undefined', () => {
23
+ expect(hasRequiredPermission(undefined, 'READ')).toBe(false);
24
+ });
25
+
26
+ it('should return false if user.permissions is undefined', () => {
27
+ const noPermissionsUser: AuthenticatedUser = {
28
+ ...user,
29
+ permissions: undefined,
30
+ };
31
+ expect(hasRequiredPermission(noPermissionsUser, 'READ')).toBe(false);
32
+ });
33
+
34
+ it('should return true for a single permission the user has', () => {
35
+ expect(hasRequiredPermission(user, 'READ')).toBe(true);
36
+ });
37
+
38
+ it('should return false for a single permission the user does not have', () => {
39
+ expect(hasRequiredPermission(user, 'UNKNOWN')).toBe(false);
40
+ });
41
+
42
+ it('should return true for comma-delimited permissions if user has ALL', () => {
43
+ expect(hasRequiredPermission(user, 'READ,WRITE')).toBe(true);
44
+ });
45
+
46
+ it('should return false for comma-delimited permissions if missing one', () => {
47
+ expect(hasRequiredPermission(user, 'READ,UPDATE_USER')).toBe(false);
48
+ });
49
+
50
+ it('should return true if user has ANY of the permissions in the array', () => {
51
+ expect(hasRequiredPermission(user, ['READ', 'UPDATE_USER'])).toBe(true);
52
+ });
53
+
54
+ it('should return false if user does not have ANY of the permissions in the array', () => {
55
+ expect(hasRequiredPermission(user, ['UPDATE_USER', 'CREATE_POST'])).toBe(
56
+ false
57
+ );
58
+ });
59
+ });
60
+
61
+ describe('hasRequiredRole', () => {
62
+ it('should return false if user is undefined', () => {
63
+ expect(hasRequiredRole(undefined, 'ADMIN')).toBe(false);
64
+ });
65
+
66
+ it('should return false if user.roles is undefined', () => {
67
+ const noRolesUser: AuthenticatedUser = { ...user, roles: undefined };
68
+ expect(hasRequiredRole(noRolesUser, 'ADMIN')).toBe(false);
69
+ });
70
+
71
+ it('should return true for a single role the user has', () => {
72
+ expect(hasRequiredRole(user, 'ADMIN')).toBe(true);
73
+ });
74
+
75
+ it('should return false for a single role the user does not have', () => {
76
+ expect(hasRequiredRole(user, 'MANAGER')).toBe(false);
77
+ });
78
+
79
+ it('should return true for comma-delimited roles if user has ALL', () => {
80
+ // user has 'ADMIN' and 'USER'
81
+ expect(hasRequiredRole(user, 'ADMIN,USER')).toBe(true);
82
+ });
83
+
84
+ it('should return false for comma-delimited roles if missing one', () => {
85
+ // user has 'ADMIN' and 'USER' but not 'MANAGER'
86
+ expect(hasRequiredRole(user, 'ADMIN,MANAGER')).toBe(false);
87
+ });
88
+
89
+ it('should return true if user has ANY of the roles in the array', () => {
90
+ expect(hasRequiredRole(user, ['USER', 'MANAGER'])).toBe(true);
91
+ });
92
+
93
+ it('should return false if user does not have ANY of the roles in the array', () => {
94
+ expect(hasRequiredRole(user, ['GUEST', 'MANAGER'])).toBe(false);
95
+ });
96
+ });
97
+
98
+ describe('convertJWTToUser', () => {
99
+ it('should return undefined if base64Token is undefined', () => {
100
+ expect(convertJWTToUser(undefined)).toBeUndefined();
101
+ });
102
+
103
+ it('should return undefined if base64Token is invalid', () => {
104
+ expect(convertJWTToUser('invalid.token')).toBeUndefined();
105
+ });
106
+
107
+ it('should return undefined if payload does not contain userName', () => {
108
+ const token =
109
+ btoa('header') + '.' + btoa(JSON.stringify({})) + '.signature';
110
+ expect(convertJWTToUser(token)).toBeUndefined();
111
+ });
112
+
113
+ it('should return a user object if payload contains userName', () => {
114
+ const payload = {
115
+ sub: 'testUser',
116
+ email: 'test@example.com',
117
+ name: 'Test User',
118
+ role: 'ADMIN',
119
+ permission: 'READ',
120
+ };
121
+ const token =
122
+ btoa('header') + '.' + btoa(JSON.stringify(payload)) + '.signature';
123
+ const user = convertJWTToUser(token);
124
+ expect(user).toEqual({
125
+ userName: 'testUser',
126
+ email: 'test@example.com',
127
+ displayName: 'Test User',
128
+ roles: ['ADMIN'],
129
+ permissions: ['READ'],
130
+ });
131
+ });
132
+
133
+ it('should return a user object if payload contains nameid', () => {
134
+ const payload = {
135
+ nameid: 'testUser',
136
+ email: 'test@example.com',
137
+ name: 'Test User',
138
+ role: 'ADMIN',
139
+ permission: 'READ',
140
+ };
141
+ const token =
142
+ btoa('header') + '.' + btoa(JSON.stringify(payload)) + '.signature';
143
+ const user = convertJWTToUser(token);
144
+ expect(user).toEqual({
145
+ userName: 'testUser',
146
+ email: 'test@example.com',
147
+ displayName: 'Test User',
148
+ roles: ['ADMIN'],
149
+ permissions: ['READ'],
150
+ });
151
+ });
152
+
153
+ it('should return undefined if an error occurs during parsing', () => {
154
+ const token =
155
+ btoa('header') + '.' + btoa('invalidPayload') + '.signature';
156
+ expect(convertJWTToUser(token)).toBeUndefined();
157
+ });
158
+ });
159
+ });