@verisoft/security-core 20.1.0 → 20.1.2
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/fesm2022/verisoft-security-core.mjs +380 -0
- package/fesm2022/verisoft-security-core.mjs.map +1 -0
- package/index.d.ts +153 -0
- package/package.json +17 -3
- package/.eslintrc.json +0 -48
- package/jest.config.ts +0 -21
- package/ng-package.json +0 -7
- package/project.json +0 -36
- package/src/index.ts +0 -1
- package/src/lib/directives/has-permission.directive.ts +0 -54
- package/src/lib/directives/has-role.directive.ts +0 -54
- package/src/lib/directives/index.ts +0 -2
- package/src/lib/guards/auth.guard.ts +0 -55
- package/src/lib/guards/index.ts +0 -1
- package/src/lib/index.ts +0 -6
- package/src/lib/models/authenticated-user.model.ts +0 -8
- package/src/lib/models/config.model.ts +0 -9
- package/src/lib/models/functions.spec.ts +0 -159
- package/src/lib/models/functions.ts +0 -103
- package/src/lib/models/index.ts +0 -3
- package/src/lib/provider.ts +0 -52
- package/src/lib/services/auth-context.service.ts +0 -38
- package/src/lib/services/index.ts +0 -7
- package/src/lib/services/local-storage-token-provider.ts +0 -23
- package/src/lib/services/local-token-provider.ts +0 -15
- package/src/lib/services/login.service.ts +0 -23
- package/src/lib/services/logout.service.ts +0 -15
- package/src/lib/services/security-initializer.ts +0 -26
- package/src/lib/services/session-token-provider.ts +0 -15
- package/src/lib/services/token-provider.ts +0 -5
- package/src/lib/state/actions.ts +0 -7
- package/src/lib/state/feature.ts +0 -10
- package/src/lib/state/index.ts +0 -4
- package/src/lib/state/reducers.ts +0 -11
- package/src/lib/state/selectors.ts +0 -9
- package/src/lib/state/state.ts +0 -9
- package/src/test-setup.ts +0 -8
- package/tsconfig.json +0 -28
- package/tsconfig.lib.json +0 -17
- package/tsconfig.lib.prod.json +0 -9
- package/tsconfig.spec.json +0 -16
package/index.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnDestroy, TemplateRef, ViewContainerRef, Provider, EnvironmentProviders, ModuleWithProviders, InjectionToken } from '@angular/core';
|
|
3
|
+
import * as _ngrx_store from '@ngrx/store';
|
|
4
|
+
import { Store } from '@ngrx/store';
|
|
5
|
+
import { Observable } from 'rxjs';
|
|
6
|
+
import { Router, CanActivate, CanActivateChild, ActivatedRouteSnapshot, UrlTree } from '@angular/router';
|
|
7
|
+
import * as _verisoft_security_core from '@verisoft/security-core';
|
|
8
|
+
|
|
9
|
+
interface AuthenticatedUser {
|
|
10
|
+
userId?: string;
|
|
11
|
+
userName: string;
|
|
12
|
+
email: string;
|
|
13
|
+
displayName?: string;
|
|
14
|
+
roles: string[] | undefined;
|
|
15
|
+
permissions: string[] | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare function hasRequiredPermission(user: AuthenticatedUser | undefined, permission: string | string[]): boolean;
|
|
19
|
+
declare function hasRequiredRole(user: AuthenticatedUser | undefined, role: string | string[]): boolean;
|
|
20
|
+
declare function convertJWTToUser(base64Token?: string): AuthenticatedUser | undefined;
|
|
21
|
+
declare function decodeJwtPayload(jwt: string): any;
|
|
22
|
+
|
|
23
|
+
interface SecurityConfig {
|
|
24
|
+
tokenStorageKey: string;
|
|
25
|
+
contextTokenStorageKey?: string;
|
|
26
|
+
loginPage?: string;
|
|
27
|
+
logoutPage?: string;
|
|
28
|
+
notAuthorizedPage?: string;
|
|
29
|
+
sendTokenHeader?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare class AuthContextService {
|
|
33
|
+
private store;
|
|
34
|
+
user$: Observable<AuthenticatedUser | undefined>;
|
|
35
|
+
isAuthenticated$: Observable<boolean>;
|
|
36
|
+
constructor(store: Store);
|
|
37
|
+
setUser(user: AuthenticatedUser | undefined): void;
|
|
38
|
+
hasRequiredPermission(requiredPermissions: string | string[]): Observable<boolean>;
|
|
39
|
+
hasRequiredRole(requiredPermissions: string | string[]): Observable<boolean>;
|
|
40
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AuthContextService, never>;
|
|
41
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AuthContextService>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface TokenProvider {
|
|
45
|
+
getToken(): Observable<string | undefined>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare class LocalStorageTokenProvider implements TokenProvider {
|
|
49
|
+
private config;
|
|
50
|
+
getToken(): Observable<string | undefined>;
|
|
51
|
+
setToken(token: string): void;
|
|
52
|
+
removeToken(): void;
|
|
53
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LocalStorageTokenProvider, never>;
|
|
54
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<LocalStorageTokenProvider>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
declare function securityInitializerFactory(tokenProvider: TokenProvider, authService: AuthContextService, config: SecurityConfig, router: Router): () => Promise<unknown>;
|
|
58
|
+
|
|
59
|
+
declare class SessionStorageTokenProvider implements TokenProvider {
|
|
60
|
+
private config;
|
|
61
|
+
getToken(): Observable<string | undefined>;
|
|
62
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SessionStorageTokenProvider, never>;
|
|
63
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SessionStorageTokenProvider>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
declare class LoginService {
|
|
67
|
+
private config;
|
|
68
|
+
private tokenProvider;
|
|
69
|
+
private authService;
|
|
70
|
+
private router;
|
|
71
|
+
login(token?: string): void;
|
|
72
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LoginService, never>;
|
|
73
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<LoginService>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare class LogoutService {
|
|
77
|
+
private readonly tokenProvider;
|
|
78
|
+
private readonly authService;
|
|
79
|
+
logout(): void;
|
|
80
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LogoutService, never>;
|
|
81
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<LogoutService>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
declare class HasPermissionDirective<T> implements OnDestroy {
|
|
85
|
+
private templateRef;
|
|
86
|
+
private viewContainer;
|
|
87
|
+
private authContext;
|
|
88
|
+
private requiredPermissions;
|
|
89
|
+
private sub?;
|
|
90
|
+
constructor(templateRef: TemplateRef<T>, viewContainer: ViewContainerRef, authContext: AuthContextService);
|
|
91
|
+
set hasPermission(value: string | string[]);
|
|
92
|
+
ngOnDestroy(): void;
|
|
93
|
+
private unregister;
|
|
94
|
+
private updateView;
|
|
95
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<HasPermissionDirective<any>, never>;
|
|
96
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<HasPermissionDirective<any>, "[hasPermission]", never, { "hasPermission": { "alias": "hasPermission"; "required": false; }; }, {}, never, never, true, never>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
declare class HasRoleDirective<T> implements OnDestroy {
|
|
100
|
+
private templateRef;
|
|
101
|
+
private viewContainer;
|
|
102
|
+
private authContext;
|
|
103
|
+
private requiredRoles;
|
|
104
|
+
private sub?;
|
|
105
|
+
constructor(templateRef: TemplateRef<T>, viewContainer: ViewContainerRef, authContext: AuthContextService);
|
|
106
|
+
set hasRole(value: string | string[]);
|
|
107
|
+
ngOnDestroy(): void;
|
|
108
|
+
private unregister;
|
|
109
|
+
private updateView;
|
|
110
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<HasRoleDirective<any>, never>;
|
|
111
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<HasRoleDirective<any>, "[hasRole]", never, { "hasRole": { "alias": "hasRole"; "required": false; }; }, {}, never, never, true, never>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
declare class AuthGuard implements CanActivate, CanActivateChild {
|
|
115
|
+
private config;
|
|
116
|
+
private router;
|
|
117
|
+
private authContext;
|
|
118
|
+
canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree>;
|
|
119
|
+
canActivateChild(childRoute: ActivatedRouteSnapshot): Observable<boolean | UrlTree>;
|
|
120
|
+
private checkPermissionsAndRolesAndNavigate;
|
|
121
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AuthGuard, never>;
|
|
122
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AuthGuard>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
declare const setUser: _ngrx_store.ActionCreator<"[Auth] Set User", (props: {
|
|
126
|
+
user: AuthenticatedUser | undefined;
|
|
127
|
+
}) => {
|
|
128
|
+
user: AuthenticatedUser | undefined;
|
|
129
|
+
} & _ngrx_store.Action<"[Auth] Set User">>;
|
|
130
|
+
|
|
131
|
+
interface AuthState {
|
|
132
|
+
user: AuthenticatedUser | undefined;
|
|
133
|
+
}
|
|
134
|
+
declare const initialState: AuthState;
|
|
135
|
+
|
|
136
|
+
declare const authReducer: _ngrx_store.ActionReducer<AuthState, _ngrx_store.Action<string>>;
|
|
137
|
+
|
|
138
|
+
declare const selectIsAuthenticated: _ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: _verisoft_security_core.AuthenticatedUser | undefined) => boolean>;
|
|
139
|
+
declare const selectUser: _ngrx_store.MemoizedSelector<Record<string, any>, _verisoft_security_core.AuthenticatedUser | undefined, (featureState: _verisoft_security_core.AuthState) => _verisoft_security_core.AuthenticatedUser | undefined>;
|
|
140
|
+
|
|
141
|
+
declare function provideSecurity(config?: Partial<SecurityConfig> | undefined): (Provider | EnvironmentProviders)[];
|
|
142
|
+
declare class SecurityModule {
|
|
143
|
+
static forRoot(config?: Partial<SecurityConfig>): ModuleWithProviders<SecurityModule>;
|
|
144
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SecurityModule, never>;
|
|
145
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<SecurityModule, never, [typeof _ngrx_store.StoreFeatureModule], never>;
|
|
146
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<SecurityModule>;
|
|
147
|
+
}
|
|
148
|
+
declare const SECURITY_CONTEXT_TOKEN_PROVIDER: InjectionToken<unknown>;
|
|
149
|
+
declare const SECURITY_CONFIG: InjectionToken<unknown>;
|
|
150
|
+
declare const SECURITY_INITIALIZER_PROVIDER: EnvironmentProviders;
|
|
151
|
+
|
|
152
|
+
export { AuthContextService, AuthGuard, HasPermissionDirective, HasRoleDirective, LocalStorageTokenProvider, LoginService, LogoutService, SECURITY_CONFIG, SECURITY_CONTEXT_TOKEN_PROVIDER, SECURITY_INITIALIZER_PROVIDER, SecurityModule, SessionStorageTokenProvider, authReducer, convertJWTToUser, decodeJwtPayload, hasRequiredPermission, hasRequiredRole, initialState, provideSecurity, securityInitializerFactory, selectIsAuthenticated, selectUser, setUser };
|
|
153
|
+
export type { AuthState, AuthenticatedUser, SecurityConfig, TokenProvider };
|
package/package.json
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verisoft/security-core",
|
|
3
|
-
"version": "20.1.
|
|
3
|
+
"version": "20.1.2",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"@angular/core": "~20.2.0",
|
|
6
6
|
"@angular/router": "~20.2.0",
|
|
7
7
|
"@ngrx/store": "~20.0.0",
|
|
8
8
|
"rxjs": "~7.8.0"
|
|
9
9
|
},
|
|
10
|
-
"sideEffects": false
|
|
11
|
-
|
|
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
|
+
"default": "./fesm2022/verisoft-security-core.mjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"tslib": "^2.3.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/.eslintrc.json
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
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/jest.config.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
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
|
-
};
|
package/ng-package.json
DELETED
package/project.json
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
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/src/libs/security/core"],
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './lib';
|
|
@@ -1,54 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
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,55 +0,0 @@
|
|
|
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
|
-
}
|
package/src/lib/guards/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './auth.guard';
|
package/src/lib/index.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
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
|
-
});
|