mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-09 15:45:12 +00:00
feat(console): integrate frontend (#95)
* feat: console frontend * chore(dependabot): cycle and npm * chore: rename citadel to zitadel, remove generated files * chore: delete go files * chore(frontend): ci steps * chore: remove docker and envoy files * chore: remove docker file * chore: working dir * chore: run proto build * add console start * chore: restructure folders * chore: remove gui build * statikFs * generate proto for console * add statik import * import * chore: try statik * chore: path * chore: path * chore: script in root * chore: order build steps * chore: go get * chore: folder traversal * chore: non empty test file * chore: gitignore * chore: gitignore * chore: statik path * chore: switch to failing FE build * fix: build * fix: project-grant-test * fix: rm test * add statik.go * go mod tidy * chore: place test, seperate test from build * chore: lint all the world * chore: ci the world instead * chore: tune docker * chore: undo container test * chore: fix run * chore: docker build * chore: test docker build * chore: go build flags * finaly * fix caos_local * go mod Co-authored-by: Livio Amstutz <[email protected]> Co-authored-by: Max Peintner <[email protected]>
This commit is contained in:
co-authored by
Livio Amstutz
Max Peintner
parent
9e32740eb8
commit
92a294f5c8
@@ -0,0 +1,45 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { AdminServicePromiseClient } from '../proto/generated/admin_grpc_web_pb';
|
||||
import { CreateOrgRequest, OrgSetUpRequest, OrgSetUpResponse, RegisterUserRequest } from '../proto/generated/admin_pb';
|
||||
import { GrpcBackendService } from './grpc-backend.service';
|
||||
import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AdminService {
|
||||
constructor(private readonly grpcService: GrpcService, private grpcBackendService: GrpcBackendService) { }
|
||||
|
||||
public async request<TReq, TResp, TMappedResp>(
|
||||
requestFn: RequestFactory<AdminServicePromiseClient, TReq, TResp>,
|
||||
request: TReq,
|
||||
responseMapper: ResponseMapper<TResp, TMappedResp>,
|
||||
metadata?: Metadata,
|
||||
): Promise<TMappedResp> {
|
||||
const mappedRequestFn = requestFn(this.grpcService.admin).bind(this.grpcService.mgmt);
|
||||
const response = await this.grpcBackendService.runRequest(
|
||||
mappedRequestFn,
|
||||
request,
|
||||
metadata,
|
||||
);
|
||||
return responseMapper(response);
|
||||
}
|
||||
|
||||
public async SetUpOrg(
|
||||
createOrgRequest: CreateOrgRequest,
|
||||
registerUserRequest: RegisterUserRequest,
|
||||
): Promise<OrgSetUpResponse> {
|
||||
const req: OrgSetUpRequest = new OrgSetUpRequest();
|
||||
|
||||
req.setOrg(createOrgRequest);
|
||||
req.setUser(registerUserRequest);
|
||||
|
||||
return await this.request(
|
||||
c => c.setUpOrg,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthInterceptorService implements HttpInterceptor {
|
||||
|
||||
constructor() { }
|
||||
|
||||
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
console.log(req.url);
|
||||
|
||||
return next.handle(req);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
|
||||
import { Metadata } from 'grpc-web';
|
||||
import { from, Observable, of } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
|
||||
import { AuthServicePromiseClient } from '../proto/generated/auth_grpc_web_pb';
|
||||
import {
|
||||
MfaOtpResponse,
|
||||
MultiFactors,
|
||||
MyProjectOrgSearchQuery,
|
||||
MyProjectOrgSearchRequest,
|
||||
MyProjectOrgSearchResponse,
|
||||
PasswordChange,
|
||||
PasswordRequest,
|
||||
UpdateUserAddressRequest,
|
||||
UpdateUserEmailRequest,
|
||||
UpdateUserPhoneRequest,
|
||||
UpdateUserProfileRequest,
|
||||
UserAddress,
|
||||
UserEmail,
|
||||
UserPhone,
|
||||
UserProfile,
|
||||
UserSessionViews,
|
||||
VerifyMfaOtp,
|
||||
VerifyUserPhoneRequest,
|
||||
} from '../proto/generated/auth_pb';
|
||||
import { GrpcBackendService } from './grpc-backend.service';
|
||||
import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthUserService {
|
||||
private _roleCache: string[] = [];
|
||||
|
||||
constructor(private readonly grpcClient: GrpcService,
|
||||
private grpcBackendService: GrpcBackendService,
|
||||
) { }
|
||||
|
||||
public async request<TReq, TResp, TMappedResp>(
|
||||
requestFn: RequestFactory<AuthServicePromiseClient, TReq, TResp>,
|
||||
request: TReq,
|
||||
responseMapper: ResponseMapper<TResp, TMappedResp>,
|
||||
metadata?: Metadata,
|
||||
): Promise<TMappedResp> {
|
||||
const mappedRequestFn = requestFn(this.grpcClient.auth).bind(this.grpcClient.auth);
|
||||
const response = await this.grpcBackendService.runRequest(
|
||||
mappedRequestFn,
|
||||
request,
|
||||
metadata,
|
||||
);
|
||||
return responseMapper(response);
|
||||
}
|
||||
|
||||
public async GetMyUserProfile(): Promise<UserProfile> {
|
||||
return await this.request(
|
||||
c => c.getMyUserProfile,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetMyMfas(): Promise<MultiFactors> {
|
||||
return await this.request(
|
||||
c => c.getMyMfas,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchMyProjectOrgs(
|
||||
limit: number,
|
||||
offset: number,
|
||||
queryList?: MyProjectOrgSearchQuery[],
|
||||
): Promise<MyProjectOrgSearchResponse> {
|
||||
const req: MyProjectOrgSearchRequest = new MyProjectOrgSearchRequest();
|
||||
req.setOffset(offset);
|
||||
req.setLimit(limit);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
|
||||
return await this.request(
|
||||
c => c.searchMyProjectOrgs,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveMyUserProfile(profile: UserProfile.AsObject): Promise<UserProfile> {
|
||||
const req = new UpdateUserProfileRequest();
|
||||
req.setFirstName(profile.firstName);
|
||||
req.setLastName(profile.lastName);
|
||||
req.setNickName(profile.nickName);
|
||||
req.setDisplayName(profile.displayName);
|
||||
req.setPreferredLanguage(profile.preferredLanguage);
|
||||
req.setGender(profile.gender);
|
||||
return await this.request(
|
||||
c => c.updateMyUserProfile,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async getMyUserSessions(): Promise<UserSessionViews> {
|
||||
return await this.request(
|
||||
c => c.getMyUserSessions,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetMyUserEmail(): Promise<UserEmail> {
|
||||
return await this.request(
|
||||
c => c.getMyUserEmail,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveMyUserEmail(email: UserEmail.AsObject): Promise<UserEmail> {
|
||||
const req = new UpdateUserEmailRequest();
|
||||
req.setEmail(email.email);
|
||||
return await this.request(
|
||||
c => c.changeMyUserEmail,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
private async getMyzitadelPermissions(): Promise<any> {
|
||||
return await this.request(
|
||||
c => c.getMyZitadelPermissions,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public GetMyzitadelPermissions(): Observable<any> {
|
||||
return from(this.getMyzitadelPermissions());
|
||||
}
|
||||
|
||||
public hasRoles(userRoles: string[], requestedRoles: string[], each: boolean = false): boolean {
|
||||
return each ?
|
||||
requestedRoles.every(role => userRoles.includes(role)) :
|
||||
requestedRoles.findIndex(role => {
|
||||
return userRoles.findIndex(i => i.includes(role)) > -1;
|
||||
// return userRoles.includes(role);
|
||||
}) > -1;
|
||||
}
|
||||
|
||||
public async GetMyUserPhone(): Promise<UserPhone> {
|
||||
// return this.grpcClient.auth.getMyUserPhone(new Empty());
|
||||
return await this.request(
|
||||
c => c.getMyUserPhone,
|
||||
new Empty(),
|
||||
(f: UserPhone) => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveMyUserPhone(phone: UserPhone.AsObject): Promise<UserPhone> {
|
||||
const req = new UpdateUserPhoneRequest();
|
||||
req.setPhone(phone.phone);
|
||||
return await this.request(
|
||||
c => c.changeMyUserPhone,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetMyUserAddress(): Promise<UserAddress> {
|
||||
return await this.request(
|
||||
c => c.getMyUserAddress,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ResendEmailVerification(): Promise<Empty> {
|
||||
const req = new Empty();
|
||||
return await this.request(
|
||||
c => c.resendMyEmailVerificationMail,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ResendPhoneVerification(): Promise<Empty> {
|
||||
const req = new Empty();
|
||||
return await this.request(
|
||||
c => c.resendMyPhoneVerificationCode,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SetMyPassword(id: string): Promise<Empty> {
|
||||
const req = new PasswordRequest();
|
||||
req.setPassword(id);
|
||||
|
||||
return await this.request(
|
||||
c => c.setMyPassword,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ChangeMyPassword(oldPassword: string, newPassword: string): Promise<Empty> {
|
||||
const req = new PasswordChange();
|
||||
req.setOldPassword(oldPassword);
|
||||
req.setNewPassword(newPassword);
|
||||
return await this.request(
|
||||
c => c.changeMyPassword,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddMfaOTP(): Promise<MfaOtpResponse> {
|
||||
return await this.request(
|
||||
c => c.addMfaOTP,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RemoveMfaOTP(): Promise<Empty> {
|
||||
return await this.request(
|
||||
c => c.removeMfaOTP,
|
||||
new Empty(),
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async VerifyMfaOTP(code: string): Promise<MfaOtpResponse> {
|
||||
const req = new VerifyMfaOtp();
|
||||
req.setCode(code);
|
||||
return await this.request(
|
||||
c => c.verifyMfaOTP,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async VerifyMyUserPhone(code: string): Promise<Empty> {
|
||||
const req = new VerifyUserPhoneRequest();
|
||||
req.setCode(code);
|
||||
return await this.request(
|
||||
c => c.verifyMyUserPhone,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveMyUserAddress(address: UserAddress.AsObject): Promise<UserAddress> {
|
||||
const req = new UpdateUserAddressRequest();
|
||||
req.setStreetAddress(address.streetAddress);
|
||||
req.setPostalCode(address.postalCode);
|
||||
req.setLocality(address.locality);
|
||||
req.setRegion(address.region);
|
||||
req.setCountry(address.country);
|
||||
return await this.request(
|
||||
c => c.updateMyUserAddress,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public isAllowed(roles: string[], each: boolean = false): Observable<boolean> {
|
||||
if (roles && roles.length > 0) {
|
||||
if (this._roleCache.length > 0) {
|
||||
return of(this.hasRoles(this._roleCache, roles));
|
||||
}
|
||||
|
||||
return this.GetMyzitadelPermissions().pipe(
|
||||
switchMap(response => {
|
||||
const userRoles = response.toObject().permissionsList;
|
||||
this._roleCache = userRoles;
|
||||
return of(this.hasRoles(userRoles, roles, each));
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
return of(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { BehaviorSubject, from, merge, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, filter, map, mergeMap, take, timeout } from 'rxjs/operators';
|
||||
|
||||
import { Org, UserProfile } from '../proto/generated/auth_pb';
|
||||
import { AuthUserService } from './auth-user.service';
|
||||
import { GrpcService } from './grpc.service';
|
||||
import { StatehandlerService } from './statehandler.service';
|
||||
import { StorageKey, StorageService } from './storage.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthService {
|
||||
private cachedOrgs: Org.AsObject[] = [];
|
||||
private _activeOrgChanged: Subject<Org.AsObject> = new Subject();
|
||||
public user!: Observable<UserProfile.AsObject>;
|
||||
private _authenticated: boolean = false;
|
||||
private readonly _authenticationChanged: BehaviorSubject<
|
||||
boolean
|
||||
> = new BehaviorSubject(this.authenticated);
|
||||
|
||||
constructor(
|
||||
private grpcService: GrpcService,
|
||||
private config: AuthConfig,
|
||||
private oauthService: OAuthService,
|
||||
private userService: AuthUserService,
|
||||
private storage: StorageService,
|
||||
private statehandler: StatehandlerService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.user = merge(
|
||||
of(this.oauthService.getAccessToken()).pipe(
|
||||
filter(token => token ? true : false),
|
||||
),
|
||||
this.oauthService.events.pipe(
|
||||
filter(e => e.type === 'token_received'),
|
||||
timeout(this.oauthService.waitForTokenInMsec || 0),
|
||||
catchError(_ => of(null)), // timeout is not an error
|
||||
map(_ => this.oauthService.getAccessToken()),
|
||||
),
|
||||
).pipe(
|
||||
take(1),
|
||||
mergeMap(token => {
|
||||
return from(this.userService.GetMyUserProfile()).pipe(map(userprofile => userprofile.toObject()));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public get authenticated(): boolean {
|
||||
return this._authenticated;
|
||||
}
|
||||
|
||||
public get authenticationChanged(): Observable<boolean> {
|
||||
return this._authenticationChanged;
|
||||
}
|
||||
|
||||
public getOIDCUser(): Observable<any> {
|
||||
return from(this.oauthService.loadUserProfile());
|
||||
}
|
||||
|
||||
public async authenticate(config?: Partial<AuthConfig>, setState: boolean = true): Promise<boolean> {
|
||||
this.config.issuer = config?.issuer || this.grpcService.issuer;
|
||||
this.config.clientId = config?.clientId || this.grpcService.clientid;
|
||||
this.config.customQueryParams = config?.customQueryParams;
|
||||
this.oauthService.configure(this.config);
|
||||
// this.oauthService.setupAutomaticSilentRefresh();
|
||||
this.oauthService.strictDiscoveryDocumentValidation = false;
|
||||
await this.oauthService.loadDiscoveryDocumentAndTryLogin();
|
||||
|
||||
this._authenticated = this.oauthService.hasValidAccessToken();
|
||||
if (!this.oauthService.hasValidIdToken() || !this.authenticated || config) {
|
||||
const newState = setState ? await this.statehandler.createState().toPromise() : undefined;
|
||||
this.oauthService.initCodeFlow(newState);
|
||||
}
|
||||
this._authenticationChanged.next(this.authenticated);
|
||||
|
||||
return this.authenticated;
|
||||
}
|
||||
|
||||
public signout(): void {
|
||||
this.oauthService.logOut();
|
||||
this._authenticated = false;
|
||||
this._authenticationChanged.next(false);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
|
||||
|
||||
public get activeOrgChanged(): Observable<Org.AsObject> {
|
||||
return this._activeOrgChanged;
|
||||
}
|
||||
|
||||
public async GetActiveOrg(id?: string): Promise<Org.AsObject> {
|
||||
if (id) {
|
||||
const org = this.storage.getItem<Org.AsObject>(StorageKey.organization);
|
||||
if (org && this.cachedOrgs.find(tmp => tmp.id === org.id)) {
|
||||
return org;
|
||||
}
|
||||
return Promise.reject(new Error('no cached org'));
|
||||
} else {
|
||||
let orgs = this.cachedOrgs;
|
||||
if (orgs.length === 0) {
|
||||
orgs = (await this.userService.SearchMyProjectOrgs(10, 0)).toObject().resultList;
|
||||
this.cachedOrgs = orgs;
|
||||
}
|
||||
|
||||
const org = this.storage.getItem<Org.AsObject>(StorageKey.organization);
|
||||
if (org && orgs.find(tmp => tmp.id === org.id)) {
|
||||
return org;
|
||||
}
|
||||
|
||||
if (orgs.length === 0) {
|
||||
return Promise.reject(new Error('No organizations found!'));
|
||||
}
|
||||
const orgToSet = orgs.find(element => element.id !== '0' && element.name !== '');
|
||||
|
||||
if (orgToSet) {
|
||||
this.setActiveOrg(orgToSet);
|
||||
return Promise.resolve(orgToSet);
|
||||
}
|
||||
return Promise.resolve(orgs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public setActiveOrg(org: Org.AsObject): void {
|
||||
this.storage.setItem(StorageKey.organization, org);
|
||||
this._activeOrgChanged.next(org);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { GrpcHandler } from './grpc-handler';
|
||||
import { GrpcInterceptor } from './grpc-interceptor';
|
||||
import { StorageService } from './storage.service';
|
||||
|
||||
const authorizationKey = 'Authorization';
|
||||
const bearerPrefix = 'Bearer ';
|
||||
const accessTokenStorageField = 'access_token';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class GrpcAuthInterceptor implements GrpcInterceptor {
|
||||
constructor(private readonly authStorage: StorageService) { }
|
||||
|
||||
public async intercept(
|
||||
req: unknown,
|
||||
metadata: Metadata,
|
||||
next: GrpcHandler,
|
||||
): Promise<any> {
|
||||
if (!metadata[authorizationKey]) {
|
||||
const accessToken = this.authStorage.getItem(accessTokenStorageField);
|
||||
if (accessToken) {
|
||||
metadata[authorizationKey] = bearerPrefix + accessToken;
|
||||
}
|
||||
}
|
||||
|
||||
return await next.handle(req, metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { Metadata } from 'grpc-web';
|
||||
import {
|
||||
GrpcDefaultHandler,
|
||||
GrpcHandler,
|
||||
GrpcInterceptorHandler,
|
||||
GrpcRequestFn,
|
||||
} from './grpc-handler';
|
||||
import { GRPC_INTERCEPTORS, GrpcInterceptor } from './grpc-interceptor';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class GrpcBackendService {
|
||||
constructor(
|
||||
@Inject(GRPC_INTERCEPTORS) private readonly interceptors: GrpcInterceptor[],
|
||||
) {}
|
||||
|
||||
public async runRequest<TReq, TResp>(
|
||||
requestFn: GrpcRequestFn<TReq, TResp>,
|
||||
request: TReq,
|
||||
metadata: Metadata = {},
|
||||
): Promise<TResp> {
|
||||
const defaultHandler: GrpcHandler = new GrpcDefaultHandler(requestFn);
|
||||
const chain = this.interceptors.reduceRight(
|
||||
(next, interceptor) => new GrpcInterceptorHandler(next, interceptor),
|
||||
defaultHandler,
|
||||
);
|
||||
return chain.handle(request, metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { GrpcInterceptor } from './grpc-interceptor';
|
||||
|
||||
export type GrpcRequestFn<TReq, TResp> = (
|
||||
request: TReq,
|
||||
metadata?: Metadata,
|
||||
) => Promise<TResp>;
|
||||
|
||||
export interface GrpcHandler {
|
||||
handle(req: unknown, metadata: Metadata): Promise<any>;
|
||||
}
|
||||
|
||||
export class GrpcInterceptorHandler implements GrpcHandler {
|
||||
constructor(
|
||||
private readonly next: GrpcHandler,
|
||||
private interceptor: GrpcInterceptor,
|
||||
) {}
|
||||
|
||||
public handle(req: unknown, metadata: Metadata): Promise<unknown> {
|
||||
return this.interceptor.intercept(req, metadata, this.next);
|
||||
}
|
||||
}
|
||||
|
||||
export class GrpcDefaultHandler<TReq, TResp> implements GrpcHandler {
|
||||
constructor(private readonly requestFn: GrpcRequestFn<TReq, TResp>) {}
|
||||
|
||||
public handle(req: TReq, metadata: Metadata): Promise<TResp> {
|
||||
return this.requestFn(req, metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { Metadata } from 'grpc-web';
|
||||
import { GrpcHandler } from './grpc-handler';
|
||||
|
||||
export const GRPC_INTERCEPTORS = new InjectionToken<GrpcInterceptor[]>(
|
||||
'GRPC_INTERCEPTORS',
|
||||
);
|
||||
|
||||
export interface GrpcInterceptor {
|
||||
intercept(req: unknown, metadata: Metadata, next: GrpcHandler): Promise<any>;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { Org } from '../proto/generated/auth_pb';
|
||||
import { GrpcHandler } from './grpc-handler';
|
||||
import { GrpcInterceptor } from './grpc-interceptor';
|
||||
import { StorageService } from './storage.service';
|
||||
|
||||
const orgKey = 'x-zitadel-orgid';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class GrpcOrgInterceptor implements GrpcInterceptor {
|
||||
constructor(private readonly storageService: StorageService) { }
|
||||
|
||||
public async intercept(
|
||||
req: unknown,
|
||||
metadata: Metadata,
|
||||
next: GrpcHandler,
|
||||
): Promise<any> {
|
||||
const org: Org.AsObject | null = (this.storageService.getItem('organization'));
|
||||
if (!metadata[orgKey] && org) {
|
||||
metadata[orgKey] = org.id ?? '';
|
||||
}
|
||||
|
||||
return await next.handle(req, metadata);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { AdminServicePromiseClient } from '../proto/generated/admin_grpc_web_pb';
|
||||
import { AuthServicePromiseClient } from '../proto/generated/auth_grpc_web_pb';
|
||||
import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb';
|
||||
import { GrpcRequestFn } from './grpc-handler';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class GrpcService {
|
||||
public issuer: string = '';
|
||||
public clientid: string = '';
|
||||
|
||||
public auth!: AuthServicePromiseClient;
|
||||
public mgmt!: ManagementServicePromiseClient;
|
||||
public admin!: AdminServicePromiseClient;
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
) { }
|
||||
|
||||
public async loadAppEnvironment(): Promise<any> {
|
||||
return this.http.get('/assets/environment.json')
|
||||
.toPromise().then((data: any) => {
|
||||
if (data && data.authServiceUrl && data.mgmtServiceUrl && data.issuer) {
|
||||
this.auth = new AuthServicePromiseClient(data.authServiceUrl);
|
||||
this.mgmt = new ManagementServicePromiseClient(data.mgmtServiceUrl);
|
||||
this.admin = new AdminServicePromiseClient(data.adminServiceUrl);
|
||||
|
||||
this.issuer = data.issuer;
|
||||
if (data.clientid) {
|
||||
this.clientid = data.clientid;
|
||||
}
|
||||
}
|
||||
return Promise.resolve(data);
|
||||
}).catch(() => {
|
||||
console.log('Failed to load environment from assets');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export type RequestFactory<TClient, TReq, TResp> = (
|
||||
client: TClient,
|
||||
) => GrpcRequestFn<TReq, TResp>;
|
||||
|
||||
export type ResponseMapper<TResp, TMappedResp> = (resp: TResp) => TMappedResp;
|
||||
@@ -0,0 +1,377 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb';
|
||||
import {
|
||||
ChangeRequest,
|
||||
Changes,
|
||||
CreateUserRequest,
|
||||
NotificationType,
|
||||
PasswordRequest,
|
||||
ProjectGrantMemberSearchQuery,
|
||||
ProjectGrantMemberSearchRequest,
|
||||
ProjectGrantMemberSearchResponse,
|
||||
ProjectRoleAdd,
|
||||
SetPasswordNotificationRequest,
|
||||
UpdateUserAddressRequest,
|
||||
UpdateUserEmailRequest,
|
||||
UpdateUserPhoneRequest,
|
||||
UpdateUserProfileRequest,
|
||||
User,
|
||||
UserAddress,
|
||||
UserEmail,
|
||||
UserEmailID,
|
||||
UserGrant,
|
||||
UserGrantCreate,
|
||||
UserGrantSearchQuery,
|
||||
UserGrantSearchRequest,
|
||||
UserGrantSearchResponse,
|
||||
UserID,
|
||||
UserPhone,
|
||||
UserProfile,
|
||||
UserSearchQuery,
|
||||
UserSearchRequest,
|
||||
UserSearchResponse,
|
||||
} from '../proto/generated/management_pb';
|
||||
import { GrpcBackendService } from './grpc-backend.service';
|
||||
import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MgmtUserService {
|
||||
constructor(private grpcService: GrpcService, private grpcBackendService: GrpcBackendService) { }
|
||||
|
||||
public async request<TReq, TResp, TMappedResp>(
|
||||
requestFn: RequestFactory<ManagementServicePromiseClient, TReq, TResp>,
|
||||
request: TReq,
|
||||
responseMapper: ResponseMapper<TResp, TMappedResp>,
|
||||
metadata?: Metadata,
|
||||
): Promise<TMappedResp> {
|
||||
const mappedRequestFn = requestFn(this.grpcService.mgmt).bind(this.grpcService.mgmt);
|
||||
const response = await this.grpcBackendService.runRequest(
|
||||
mappedRequestFn,
|
||||
request,
|
||||
metadata,
|
||||
);
|
||||
return responseMapper(response);
|
||||
}
|
||||
|
||||
public async CreateUser(user: CreateUserRequest.AsObject): Promise<User> {
|
||||
const req = new CreateUserRequest();
|
||||
req.setEmail(user.email);
|
||||
req.setUserName(user.userName);
|
||||
req.setFirstName(user.firstName);
|
||||
req.setLastName(user.lastName);
|
||||
req.setNickName(user.nickName);
|
||||
req.setDisplayName(user.displayName);
|
||||
req.setPassword(user.password);
|
||||
req.setPreferredLanguage(user.preferredLanguage);
|
||||
req.setGender(user.gender);
|
||||
req.setPhone(user.phone);
|
||||
req.setStreetAddress(user.streetAddress);
|
||||
req.setPostalCode(user.postalCode);
|
||||
req.setLocality(user.locality);
|
||||
req.setRegion(user.region);
|
||||
req.setCountry(user.country);
|
||||
return await this.request(
|
||||
c => c.createUser,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserProfile(id: string): Promise<UserProfile> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.getUserProfile,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveUserProfile(profile: UserProfile.AsObject): Promise<UserProfile> {
|
||||
const req = new UpdateUserProfileRequest();
|
||||
req.setId(profile.id);
|
||||
req.setFirstName(profile.firstName);
|
||||
req.setLastName(profile.lastName);
|
||||
req.setNickName(profile.nickName);
|
||||
req.setDisplayName(profile.displayName);
|
||||
req.setPreferredLanguage(profile.preferredLanguage);
|
||||
req.setGender(profile.gender);
|
||||
return await this.request(
|
||||
c => c.updateUserProfile,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserEmail(id: string): Promise<UserEmail> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.getUserEmail,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveUserEmail(email: UserEmail.AsObject): Promise<UserEmail> {
|
||||
const req = new UpdateUserEmailRequest();
|
||||
req.setId(email.id);
|
||||
req.setEmail(email.email);
|
||||
return await this.request(
|
||||
c => c.changeUserEmail,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserPhone(id: string): Promise<UserPhone> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.getUserPhone,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveUserPhone(phone: UserPhone.AsObject): Promise<UserPhone> {
|
||||
const req = new UpdateUserPhoneRequest();
|
||||
req.setId(phone.id);
|
||||
req.setPhone(phone.phone);
|
||||
return await this.request(
|
||||
c => c.changeUserPhone,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeactivateUser(id: string): Promise<UserPhone> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.deactivateUser,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreateUserGrant(
|
||||
projectId: string,
|
||||
userId: string,
|
||||
roleNamesList: string[],
|
||||
): Promise<UserGrant> {
|
||||
const req = new UserGrantCreate();
|
||||
req.setProjectId(projectId);
|
||||
req.setUserId(userId);
|
||||
req.setRoleKeysList(roleNamesList);
|
||||
|
||||
return await this.request(
|
||||
c => c.createUserGrant,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ReactivateUser(id: string): Promise<UserPhone> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.reactivateUser,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddRole(id: string, key: string, displayName: string, group: string): Promise<Empty> {
|
||||
const req = new ProjectRoleAdd();
|
||||
req.setId(id);
|
||||
req.setKey(key);
|
||||
req.setDisplayName(displayName);
|
||||
req.setGroup(group);
|
||||
return await this.request(
|
||||
c => c.addProjectRole,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserAddress(id: string): Promise<UserAddress> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.getUserAddress,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ResendEmailVerification(id: string): Promise<any> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.resendEmailVerificationMail,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ResendPhoneVerification(id: string): Promise<any> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.resendPhoneVerificationCode,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SetInitialPassword(id: string, password: string): Promise<any> {
|
||||
const req = new PasswordRequest();
|
||||
req.setId(id);
|
||||
req.setPassword(password);
|
||||
return await this.request(
|
||||
c => c.setInitialPassword,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SendSetPasswordNotification(id: string, type: NotificationType): Promise<any> {
|
||||
const req = new SetPasswordNotificationRequest();
|
||||
req.setId(id);
|
||||
req.setType(type);
|
||||
return await this.request(
|
||||
c => c.sendSetPasswordNotification,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SaveUserAddress(address: UserAddress.AsObject): Promise<UserAddress> {
|
||||
const req = new UpdateUserAddressRequest();
|
||||
req.setId(address.id);
|
||||
req.setStreetAddress(address.streetAddress);
|
||||
req.setPostalCode(address.postalCode);
|
||||
req.setLocality(address.locality);
|
||||
req.setRegion(address.region);
|
||||
req.setCountry(address.country);
|
||||
return await this.request(
|
||||
c => c.updateUserAddress,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchProjectGrantMembers(
|
||||
limit: number,
|
||||
offset: number,
|
||||
query?: ProjectGrantMemberSearchQuery[],
|
||||
): Promise<ProjectGrantMemberSearchResponse> {
|
||||
const req = new ProjectGrantMemberSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (query) {
|
||||
req.setQueriesList(query);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchProjectGrantMembers,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchUsers(limit: number, offset: number, queryList?: UserSearchQuery[]): Promise<UserSearchResponse> {
|
||||
const req = new UserSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchUsers,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetUserByEmailGlobal(email: string): Promise<User> {
|
||||
const req = new UserEmailID();
|
||||
req.setEmail(email);
|
||||
return await this.request(
|
||||
c => c.getUserByEmailGlobal,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchUserGrants(
|
||||
limit: number,
|
||||
offset: number,
|
||||
queryList?: UserGrantSearchQuery[],
|
||||
): Promise<UserGrantSearchResponse> {
|
||||
const req = new UserGrantSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchUserGrants,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ApplicationChanges(id: string, limit: number, offset: number): Promise<Changes> {
|
||||
const req = new ChangeRequest();
|
||||
req.setId(id);
|
||||
req.setLimit(limit);
|
||||
req.setSequenceOffset(offset);
|
||||
return await this.request(
|
||||
c => c.applicationChanges,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async OrgChanges(id: string, limit: number, offset: number): Promise<Changes> {
|
||||
const req = new ChangeRequest();
|
||||
req.setId(id);
|
||||
req.setLimit(limit);
|
||||
req.setSequenceOffset(offset);
|
||||
return await this.request(
|
||||
c => c.orgChanges,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ProjectChanges(id: string, limit: number, offset: number): Promise<Changes> {
|
||||
const req = new ChangeRequest();
|
||||
req.setId(id);
|
||||
req.setLimit(limit);
|
||||
req.setSequenceOffset(offset);
|
||||
return await this.request(
|
||||
c => c.projectChanges,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UserChanges(id: string, limit: number, sequenceoffset: number): Promise<Changes> {
|
||||
const req = new ChangeRequest();
|
||||
req.setId(id);
|
||||
req.setLimit(limit);
|
||||
req.setSequenceOffset(sequenceoffset);
|
||||
return await this.request(
|
||||
c => c.userChanges,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb';
|
||||
import {
|
||||
AddOrgMemberRequest,
|
||||
Org,
|
||||
OrgDomain,
|
||||
OrgID,
|
||||
OrgMemberRoles,
|
||||
OrgMemberSearchRequest,
|
||||
OrgMemberSearchResponse,
|
||||
PasswordAgePolicy,
|
||||
PasswordAgePolicyCreate,
|
||||
PasswordAgePolicyID,
|
||||
PasswordAgePolicyUpdate,
|
||||
PasswordComplexityPolicy,
|
||||
PasswordComplexityPolicyCreate,
|
||||
PasswordComplexityPolicyID,
|
||||
PasswordComplexityPolicyUpdate,
|
||||
PasswordLockoutPolicy,
|
||||
PasswordLockoutPolicyCreate,
|
||||
PasswordLockoutPolicyID,
|
||||
PasswordLockoutPolicyUpdate,
|
||||
ProjectGrant,
|
||||
ProjectGrantCreate,
|
||||
RemoveOrgMemberRequest,
|
||||
} from '../proto/generated/management_pb';
|
||||
import { GrpcBackendService } from './grpc-backend.service';
|
||||
import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class OrgService {
|
||||
constructor(private readonly grpcService: GrpcService, private grpcBackendService: GrpcBackendService) { }
|
||||
|
||||
public async request<TReq, TResp, TMappedResp>(
|
||||
requestFn: RequestFactory<ManagementServicePromiseClient, TReq, TResp>,
|
||||
request: TReq,
|
||||
responseMapper: ResponseMapper<TResp, TMappedResp>,
|
||||
metadata?: Metadata,
|
||||
): Promise<TMappedResp> {
|
||||
const mappedRequestFn = requestFn(this.grpcService.mgmt).bind(this.grpcService.mgmt);
|
||||
const response = await this.grpcBackendService.runRequest(
|
||||
mappedRequestFn,
|
||||
request,
|
||||
metadata,
|
||||
);
|
||||
return responseMapper(response);
|
||||
}
|
||||
|
||||
public async GetOrgById(orgId: string): Promise<Org> {
|
||||
const req: OrgID = new OrgID();
|
||||
req.setId(orgId);
|
||||
return await this.request(
|
||||
c => c.getOrgByID,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchOrgMembers(orgId: string, limit: number, offset: number): Promise<OrgMemberSearchResponse> {
|
||||
const req = new OrgMemberSearchRequest();
|
||||
req.setOrgId(orgId);
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
return await this.request(
|
||||
c => c.searchOrgMembers,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async getOrgByDomainGlobal(domain: string): Promise<Org> {
|
||||
const req = new OrgDomain();
|
||||
req.setDomain(domain);
|
||||
return await this.request(
|
||||
c => c.getOrgByDomainGlobal,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddOrgMember(orgId: string, userId: string, rolesList: string[]): Promise<Empty> {
|
||||
const req = new AddOrgMemberRequest();
|
||||
req.setOrgId(orgId);
|
||||
req.setUserId(userId);
|
||||
if (rolesList) {
|
||||
req.setRolesList(rolesList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.addOrgMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RemoveOrgMember(orgId: string, userId: string): Promise<Empty> {
|
||||
const req = new RemoveOrgMemberRequest();
|
||||
req.setOrgId(orgId);
|
||||
req.setUserId(userId);
|
||||
return await this.request(
|
||||
c => c.removeOrgMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeactivateOrg(id: string): Promise<Org> {
|
||||
const req = new OrgID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.deactivateOrg,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ReactivateOrg(id: string): Promise<Org> {
|
||||
const req = new OrgID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.reactivateOrg,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreateProjectGrant(
|
||||
projectId: string,
|
||||
orgId: string,
|
||||
roleKeysList: string[],
|
||||
): Promise<ProjectGrant> {
|
||||
const req = new ProjectGrantCreate();
|
||||
req.setProjectId(projectId);
|
||||
req.setGrantedOrgId(orgId);
|
||||
req.setRoleKeysList(roleKeysList);
|
||||
return await this.request(
|
||||
c => c.createProjectGrant,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetOrgMemberRoles(): Promise<OrgMemberRoles> {
|
||||
const req = new Empty();
|
||||
return await this.request(
|
||||
c => c.getOrgMemberRoles,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
// Policy
|
||||
|
||||
public async GetPasswordAgePolicy(): Promise<PasswordAgePolicy> {
|
||||
const req = new Empty();
|
||||
|
||||
return await this.request(
|
||||
c => c.getPasswordAgePolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreatePasswordAgePolicy(
|
||||
description: string,
|
||||
maxAgeDays: number,
|
||||
expireWarnDays: number,
|
||||
): Promise<PasswordAgePolicy> {
|
||||
const req = new PasswordAgePolicyCreate();
|
||||
req.setDescription(description);
|
||||
req.setMaxAgeDays(maxAgeDays);
|
||||
req.setExpireWarnDays(expireWarnDays);
|
||||
|
||||
return await this.request(
|
||||
c => c.createPasswordAgePolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeletePasswordAgePolicy(id: string): Promise<Empty> {
|
||||
const req = new PasswordAgePolicyID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.deletePasswordAgePolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdatePasswordAgePolicy(
|
||||
description: string,
|
||||
maxAgeDays: number,
|
||||
expireWarnDays: number,
|
||||
): Promise<PasswordAgePolicy> {
|
||||
const req = new PasswordAgePolicyUpdate();
|
||||
req.setDescription(description);
|
||||
req.setMaxAgeDays(maxAgeDays);
|
||||
req.setExpireWarnDays(expireWarnDays);
|
||||
return await this.request(
|
||||
c => c.updatePasswordAgePolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetPasswordComplexityPolicy(): Promise<PasswordComplexityPolicy> {
|
||||
const req = new Empty();
|
||||
|
||||
return await this.request(
|
||||
c => c.getPasswordComplexityPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreatePasswordComplexityPolicy(
|
||||
description: string,
|
||||
hasLowerCase: boolean,
|
||||
hasUpperCase: boolean,
|
||||
hasNumber: boolean,
|
||||
hasSymbol: boolean,
|
||||
minLength: number,
|
||||
): Promise<PasswordComplexityPolicy> {
|
||||
const req = new PasswordComplexityPolicyCreate();
|
||||
req.setDescription(description);
|
||||
req.setHasLowercase(hasLowerCase);
|
||||
req.setHasUppercase(hasUpperCase);
|
||||
req.setHasNumber(hasNumber);
|
||||
req.setHasSymbol(hasSymbol);
|
||||
req.setMinLength(minLength);
|
||||
return await this.request(
|
||||
c => c.createPasswordComplexityPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeletePasswordComplexityPolicy(id: string): Promise<Empty> {
|
||||
const req = new PasswordComplexityPolicyID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.deletePasswordComplexityPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdatePasswordComplexityPolicy(
|
||||
description: string,
|
||||
hasLowerCase: boolean,
|
||||
hasUpperCase: boolean,
|
||||
hasNumber: boolean,
|
||||
hasSymbol: boolean,
|
||||
minLength: number,
|
||||
): Promise<PasswordComplexityPolicy> {
|
||||
const req = new PasswordComplexityPolicyUpdate();
|
||||
req.setDescription(description);
|
||||
req.setHasLowercase(hasLowerCase);
|
||||
req.setHasUppercase(hasUpperCase);
|
||||
req.setHasNumber(hasNumber);
|
||||
req.setHasSymbol(hasSymbol);
|
||||
req.setMinLength(minLength);
|
||||
return await this.request(
|
||||
c => c.updatePasswordComplexityPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetPasswordLockoutPolicy(): Promise<PasswordLockoutPolicy> {
|
||||
const req = new Empty();
|
||||
|
||||
return await this.request(
|
||||
c => c.getPasswordLockoutPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreatePasswordLockoutPolicy(
|
||||
description: string,
|
||||
maxAttempts: number,
|
||||
showLockoutFailures: boolean,
|
||||
): Promise<PasswordLockoutPolicy> {
|
||||
const req = new PasswordLockoutPolicyCreate();
|
||||
req.setDescription(description);
|
||||
req.setMaxAttempts(maxAttempts);
|
||||
req.setShowLockOutFailures(showLockoutFailures);
|
||||
|
||||
return await this.request(
|
||||
c => c.createPasswordLockoutPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeletePasswordLockoutPolicy(id: string): Promise<Empty> {
|
||||
const req = new PasswordLockoutPolicyID();
|
||||
req.setId(id);
|
||||
|
||||
return await this.request(
|
||||
c => c.deletePasswordLockoutPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdatePasswordLockoutPolicy(
|
||||
description: string,
|
||||
maxAttempts: number,
|
||||
showLockoutFailures: boolean,
|
||||
): Promise<PasswordLockoutPolicy> {
|
||||
const req = new PasswordLockoutPolicyUpdate();
|
||||
req.setDescription(description);
|
||||
req.setMaxAttempts(maxAttempts);
|
||||
req.setShowLockOutFailures(showLockoutFailures);
|
||||
return await this.request(
|
||||
c => c.updatePasswordLockoutPolicy,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Empty } from 'google-protobuf/google/protobuf/empty_pb';
|
||||
import { Metadata } from 'grpc-web';
|
||||
|
||||
import { ManagementServicePromiseClient } from '../proto/generated/management_grpc_web_pb';
|
||||
import {
|
||||
Application,
|
||||
ApplicationID,
|
||||
ApplicationSearchQuery,
|
||||
ApplicationSearchRequest,
|
||||
ApplicationSearchResponse,
|
||||
ApplicationUpdate,
|
||||
GrantedGrantID,
|
||||
OIDCApplicationCreate,
|
||||
OIDCConfig,
|
||||
OIDCConfigUpdate,
|
||||
Project,
|
||||
ProjectCreateRequest,
|
||||
ProjectGrant,
|
||||
ProjectGrantCreate,
|
||||
ProjectGrantID,
|
||||
ProjectGrantMemberAdd,
|
||||
ProjectGrantMemberRemove,
|
||||
ProjectGrantMemberRoles,
|
||||
ProjectGrantMemberSearchQuery,
|
||||
ProjectGrantMemberSearchRequest,
|
||||
ProjectGrantSearchRequest,
|
||||
ProjectGrantSearchResponse,
|
||||
ProjectID,
|
||||
ProjectMemberAdd,
|
||||
ProjectMemberChange,
|
||||
ProjectMemberRemove,
|
||||
ProjectMemberRoles,
|
||||
ProjectMemberSearchRequest,
|
||||
ProjectMemberSearchResponse,
|
||||
ProjectRoleAdd,
|
||||
ProjectRoleRemove,
|
||||
ProjectRoleSearchQuery,
|
||||
ProjectRoleSearchRequest,
|
||||
ProjectRoleSearchResponse,
|
||||
ProjectSearchQuery,
|
||||
ProjectSearchRequest,
|
||||
ProjectSearchResponse,
|
||||
ProjectUpdateRequest,
|
||||
ProjectUserGrantSearchRequest,
|
||||
UserGrant,
|
||||
UserGrantCreate,
|
||||
UserGrantSearchQuery,
|
||||
UserGrantSearchResponse,
|
||||
} from '../proto/generated/management_pb';
|
||||
import { GrpcBackendService } from './grpc-backend.service';
|
||||
import { GrpcService, RequestFactory, ResponseMapper } from './grpc.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ProjectService {
|
||||
constructor(private readonly grpcService: GrpcService, private grpcBackendService: GrpcBackendService) { }
|
||||
|
||||
public async request<TReq, TResp, TMappedResp>(
|
||||
requestFn: RequestFactory<ManagementServicePromiseClient, TReq, TResp>,
|
||||
request: TReq,
|
||||
responseMapper: ResponseMapper<TResp, TMappedResp>,
|
||||
metadata?: Metadata,
|
||||
): Promise<TMappedResp> {
|
||||
const mappedRequestFn = requestFn(this.grpcService.mgmt).bind(this.grpcService.mgmt);
|
||||
const response = await this.grpcBackendService.runRequest(
|
||||
mappedRequestFn,
|
||||
request,
|
||||
metadata,
|
||||
);
|
||||
return responseMapper(response);
|
||||
}
|
||||
|
||||
public async SearchProjects(
|
||||
limit: number, offset: number, queryList?: ProjectSearchQuery[]): Promise<ProjectSearchResponse> {
|
||||
const req = new ProjectSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchProjects,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetProjectById(projectId: string): Promise<Project> {
|
||||
const req = new ProjectID();
|
||||
req.setId(projectId);
|
||||
return await this.request(
|
||||
c => c.projectByID,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreateProject(project: ProjectCreateRequest.AsObject): Promise<Project> {
|
||||
const req = new ProjectCreateRequest();
|
||||
req.setName(project.name);
|
||||
return await this.request(
|
||||
c => c.createProject,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdateProject(project: Project.AsObject): Promise<Project> {
|
||||
const req = new ProjectUpdateRequest();
|
||||
req.setName(project.name);
|
||||
req.setId(project.id);
|
||||
return await this.request(
|
||||
c => c.updateProject,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ChangeProjectMember(id: string, userId: string, rolesList: string[]): Promise<Empty> {
|
||||
const req = new ProjectMemberChange();
|
||||
req.setId(id);
|
||||
req.setUserId(userId);
|
||||
req.setRolesList(rolesList);
|
||||
return await this.request(
|
||||
c => c.changeProjectMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DeactivateProject(projectId: string): Promise<Project> {
|
||||
const req = new ProjectID();
|
||||
req.setId(projectId);
|
||||
return await this.request(
|
||||
c => c.deactivateProject,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ReactivateProject(projectId: string): Promise<Project> {
|
||||
const req = new ProjectID();
|
||||
req.setId(projectId);
|
||||
return await this.request(
|
||||
c => c.reactivateProject,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchProjectGrants(projectId: string, limit: number, offset: number): Promise<ProjectGrantSearchResponse> {
|
||||
const req = new ProjectGrantSearchRequest();
|
||||
req.setProjectId(projectId);
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
return await this.request(
|
||||
c => c.searchProjectGrants,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetProjectGrantMemberRoles(): Promise<ProjectGrantMemberRoles> {
|
||||
const req = new Empty();
|
||||
return await this.request(
|
||||
c => c.getProjectGrantMemberRoles,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddProjectGrantMember(
|
||||
projectId: string,
|
||||
grantId: string,
|
||||
userId: string,
|
||||
rolesList: string[],
|
||||
): Promise<Empty> {
|
||||
const req = new ProjectGrantMemberAdd();
|
||||
req.setProjectId(projectId);
|
||||
req.setGrantId(grantId);
|
||||
req.setUserId(userId);
|
||||
req.setRolesList(rolesList);
|
||||
return await this.request(
|
||||
c => c.addProjectGrantMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchProjectGrantMembers(
|
||||
projectId: string,
|
||||
grantId: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
queryList?: ProjectGrantMemberSearchQuery[],
|
||||
): Promise<ProjectMemberSearchResponse> {
|
||||
const req = new ProjectGrantMemberSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
req.setProjectId(projectId);
|
||||
req.setGrantId(grantId);
|
||||
return await this.request(
|
||||
c => c.searchProjectGrantMembers,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RemoveProjectGrantMember(
|
||||
projectId: string,
|
||||
grantId: string,
|
||||
userId: string,
|
||||
): Promise<Empty> {
|
||||
const req = new ProjectGrantMemberRemove();
|
||||
req.setProjectId(projectId);
|
||||
req.setGrantId(grantId);
|
||||
req.setUserId(userId);
|
||||
return await this.request(
|
||||
c => c.removeProjectGrantMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public async CreateProjectGrant(orgId: string, projectId: string, roleKeys: string[]): Promise<ProjectGrant> {
|
||||
const req = new ProjectGrantCreate();
|
||||
req.setGrantedOrgId(orgId);
|
||||
req.setProjectId(projectId);
|
||||
req.setRoleKeysList(roleKeys);
|
||||
return await this.request(
|
||||
c => c.createProjectGrant,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ReactivateApplication(appId: string): Promise<Application> {
|
||||
const req = new ApplicationID();
|
||||
req.setId(appId);
|
||||
return await this.request(
|
||||
c => c.reactivateApplication,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async DectivateApplication(projectId: string): Promise<Application> {
|
||||
const req = new ApplicationID();
|
||||
req.setId(projectId);
|
||||
return await this.request(
|
||||
c => c.deactivateApplication,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RegenerateOIDCClientSecret(id: string): Promise<any> {
|
||||
const req = new ApplicationID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.regenerateOIDCClientSecret,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchProjectRoles(
|
||||
projectId: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
queryList?: ProjectRoleSearchQuery[],
|
||||
): Promise<ProjectRoleSearchResponse> {
|
||||
const req = new ProjectRoleSearchRequest();
|
||||
req.setProjectId(projectId);
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchProjectRoles,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddProjectRole(role: ProjectRoleAdd.AsObject): Promise<Empty> {
|
||||
const req = new ProjectRoleAdd();
|
||||
req.setId(role.id);
|
||||
req.setDisplayName(role.displayName);
|
||||
req.setKey(role.key);
|
||||
req.setGroup(role.group);
|
||||
return await this.request(
|
||||
c => c.addProjectRole,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RemoveProjectRole(projectId: string, key: string): Promise<Empty> {
|
||||
const req = new ProjectRoleRemove();
|
||||
req.setId(projectId);
|
||||
req.setKey(key);
|
||||
return await this.request(
|
||||
c => c.removeProjectRole,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async RemoveProjectMember(id: string, userId: string): Promise<Empty> {
|
||||
const req = new ProjectMemberRemove();
|
||||
req.setId(id);
|
||||
req.setUserId(userId);
|
||||
return await this.request(
|
||||
c => c.removeProjectMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchProjectMembers(projectId: string,
|
||||
limit: number, offset: number): Promise<ProjectMemberSearchResponse> {
|
||||
const req = new ProjectMemberSearchRequest();
|
||||
req.setProjectId(projectId);
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
return await this.request(
|
||||
c => c.searchProjectMembers,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async SearchApplications(
|
||||
projectId: string,
|
||||
limit: number,
|
||||
offset: number,
|
||||
queryList?: ApplicationSearchQuery[]): Promise<ApplicationSearchResponse> {
|
||||
const req = new ApplicationSearchRequest();
|
||||
req.setProjectId(projectId);
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchApplications,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetApplicationById(projectId: string, applicationId: string): Promise<Application> {
|
||||
const req = new ApplicationID();
|
||||
req.setProjectId(projectId);
|
||||
req.setId(applicationId);
|
||||
return await this.request(
|
||||
c => c.applicationByID,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
// NEW
|
||||
public async GetGrantedProjectGrantByID(id: string): Promise<ProjectGrant> {
|
||||
const req = new GrantedGrantID();
|
||||
req.setId(id);
|
||||
return await this.request(
|
||||
c => c.getGrantedProjectGrantByID,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async GetProjectMemberRoles(): Promise<ProjectMemberRoles> {
|
||||
const req = new Empty();
|
||||
return await this.request(
|
||||
c => c.getProjectMemberRoles,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async ProjectGrantByID(id: string): Promise<ProjectGrant> {
|
||||
const req = new ProjectGrantID();
|
||||
return await this.request(
|
||||
c => c.projectGrantByID,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
// ********* */
|
||||
|
||||
public async SearchProjectUserGrants(
|
||||
projectId: string,
|
||||
offset: number,
|
||||
limit: number,
|
||||
queryList?: UserGrantSearchQuery[],
|
||||
): Promise<UserGrantSearchResponse> {
|
||||
const req = new ProjectUserGrantSearchRequest();
|
||||
req.setLimit(limit);
|
||||
req.setOffset(offset);
|
||||
req.setProjectId(projectId);
|
||||
if (queryList) {
|
||||
req.setQueriesList(queryList);
|
||||
}
|
||||
return await this.request(
|
||||
c => c.searchProjectUserGrants,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async CreateProjectUserGrant(
|
||||
projectId: string,
|
||||
userId: string,
|
||||
roleKeysList: string[],
|
||||
): Promise<UserGrant> {
|
||||
const req = new UserGrantCreate();
|
||||
req.setProjectId(projectId);
|
||||
req.setRoleKeysList(roleKeysList);
|
||||
req.setUserId(userId);
|
||||
|
||||
return await this.request(
|
||||
c => c.createProjectUserGrant,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
// ********* */
|
||||
|
||||
public async CreateOIDCApp(app: OIDCApplicationCreate.AsObject): Promise<Application> {
|
||||
const req = new OIDCApplicationCreate();
|
||||
req.setProjectId(app.projectId);
|
||||
req.setName(app.name);
|
||||
req.setRedirectUrisList(app.redirectUrisList);
|
||||
req.setResponseTypesList(app.responseTypesList);
|
||||
req.setGrantTypesList(app.grantTypesList);
|
||||
req.setApplicationType(app.applicationType);
|
||||
req.setAuthMethodType(app.authMethodType);
|
||||
req.setPostLogoutRedirectUrisList(app.postLogoutRedirectUrisList);
|
||||
|
||||
return await this.request(
|
||||
c => c.createOIDCApplication,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdateApplication(projectId: string, appId: string, name: string): Promise<Application> {
|
||||
const req = new ApplicationUpdate();
|
||||
req.setId(appId);
|
||||
req.setName(name);
|
||||
req.setProjectId(projectId);
|
||||
return await this.request(
|
||||
c => c.updateApplication,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async UpdateOIDCAppConfig(projectId: string,
|
||||
appId: string, oidcConfig: OIDCConfig.AsObject): Promise<OIDCConfig> {
|
||||
const req = new OIDCConfigUpdate();
|
||||
req.setProjectId(projectId);
|
||||
req.setApplicationId(appId);
|
||||
req.setRedirectUrisList(oidcConfig.redirectUrisList);
|
||||
req.setResponseTypesList(oidcConfig.responseTypesList);
|
||||
req.setAuthMethodType(oidcConfig.authMethodType);
|
||||
req.setPostLogoutRedirectUrisList(oidcConfig.postLogoutRedirectUrisList);
|
||||
req.setGrantTypesList(oidcConfig.grantTypesList);
|
||||
req.setApplicationType(oidcConfig.applicationType);
|
||||
return await this.request(
|
||||
c => c.updateApplicationOIDCConfig,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
|
||||
public async AddProjectMember(projectId: string, userId: string, rolesList: string[]): Promise<Empty> {
|
||||
const req = new ProjectMemberAdd();
|
||||
req.setId(projectId);
|
||||
req.setUserId(userId);
|
||||
req.setRolesList(rolesList);
|
||||
return await this.request(
|
||||
c => c.addProjectMember,
|
||||
req,
|
||||
f => f,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export abstract class StatehandlerProcessorService {
|
||||
public abstract createState(url: string): Observable<string | undefined>;
|
||||
public abstract restoreState(state?: string): void;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class StatehandlerProcessorServiceImpl
|
||||
implements StatehandlerProcessorService {
|
||||
constructor(private location: Location) { }
|
||||
|
||||
public createState(url: string): Observable<string> {
|
||||
const externalUrl = this.location.prepareExternalUrl(url);
|
||||
const urlId = uuidv4();
|
||||
|
||||
sessionStorage.setItem(urlId, externalUrl);
|
||||
|
||||
return of(urlId);
|
||||
}
|
||||
|
||||
public restoreState(state?: string): void {
|
||||
if (state === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = sessionStorage.getItem(state);
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = window.location.origin + url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Injectable, Injector, OnDestroy, Type } from '@angular/core';
|
||||
import { GuardsCheckStart, Router, RouterEvent } from '@angular/router';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { Observable, Subject, throwError } from 'rxjs';
|
||||
import { filter, map, shareReplay, switchMap, take, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { StatehandlerProcessorService } from './statehandler-processor.service';
|
||||
|
||||
export abstract class StatehandlerService {
|
||||
public abstract createState(): Observable<string | undefined>;
|
||||
public abstract initStateHandler(): void;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class StatehandlerServiceImpl
|
||||
implements StatehandlerService, OnDestroy {
|
||||
private events?: Observable<string>;
|
||||
private unsubscribe$: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
oauthService: OAuthService,
|
||||
private injector: Injector,
|
||||
private processor: StatehandlerProcessorService,
|
||||
) {
|
||||
oauthService.events
|
||||
.pipe(
|
||||
filter(event => event.type === 'token_received'),
|
||||
map(() => oauthService.state),
|
||||
takeUntil(this.unsubscribe$),
|
||||
)
|
||||
.subscribe(state => processor.restoreState(state));
|
||||
}
|
||||
|
||||
public initStateHandler(): void {
|
||||
const router = this.injector.get(Router as Type<Router>);
|
||||
this.events = (router.events as Observable<RouterEvent>).pipe(
|
||||
filter(event => event instanceof GuardsCheckStart),
|
||||
map(event => event.url),
|
||||
shareReplay(1),
|
||||
);
|
||||
|
||||
this.events.pipe(takeUntil(this.unsubscribe$)).subscribe();
|
||||
}
|
||||
|
||||
public createState(): Observable<string | undefined> {
|
||||
if (this.events === undefined) {
|
||||
return throwError('no router events');
|
||||
}
|
||||
|
||||
return this.events.pipe(
|
||||
take(1),
|
||||
switchMap(url => this.processor.createState(url)),
|
||||
);
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.unsubscribe$.next();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { OAuthStorage } from 'angular-oauth2-oidc';
|
||||
|
||||
import { GrpcService } from './grpc.service';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
|
||||
export class StorageService implements OAuthStorage {
|
||||
private storage: Storage = window.sessionStorage;
|
||||
|
||||
constructor(private grpcService: GrpcService) { }
|
||||
|
||||
public setItem<TValue = string>(key: string, value: TValue): void {
|
||||
this.storage.setItem(this.getPrefixedKey(key), JSON.stringify(value));
|
||||
}
|
||||
|
||||
public getItem<TResult = string>(key: string): TResult | null {
|
||||
const result = this.storage.getItem(this.getPrefixedKey(key));
|
||||
if (result) {
|
||||
return JSON.parse(result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public removeItem(key: string): void {
|
||||
this.storage.removeItem(this.getPrefixedKey(key));
|
||||
}
|
||||
|
||||
public getPrefixedKey(key: string): string {
|
||||
return `caos:${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class StorageConfig {
|
||||
clientId: string = '';
|
||||
storage: Storage = window.sessionStorage;
|
||||
}
|
||||
|
||||
export enum StorageKey {
|
||||
organization = 'organization',
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class ThemeService {
|
||||
private _darkTheme: Subject<boolean> = new Subject<boolean>();
|
||||
public isDarkTheme: Observable<boolean> = this._darkTheme.asObservable();
|
||||
|
||||
setDarkTheme(isDarkTheme: boolean): void {
|
||||
this._darkTheme.next(isDarkTheme);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToastService {
|
||||
constructor(private snackBar: MatSnackBar) { }
|
||||
|
||||
public showInfo(message: string): void {
|
||||
this.showMessage(message, 'close');
|
||||
}
|
||||
|
||||
public showError(message: string): void {
|
||||
this.showMessage(message, 'close');
|
||||
}
|
||||
|
||||
private showMessage(message: string, action: string): void {
|
||||
this.snackBar.open(message, action, {
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UpdateService {
|
||||
constructor(private swUpdate: SwUpdate, snackbar: MatSnackBar) {
|
||||
this.swUpdate.available.subscribe((evt) => {
|
||||
const snack = snackbar.open('Update Available', 'Reload');
|
||||
|
||||
snack.onAction().subscribe(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user