mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 15:07:24 +00:00
Merge branch 'main' into next
This commit is contained in:
commit
c667ab7047
1
.github/workflows/e2e.yml
vendored
1
.github/workflows/e2e.yml
vendored
@ -50,7 +50,6 @@ jobs:
|
||||
with:
|
||||
working-directory: e2e
|
||||
browser: ${{ matrix.browser }}
|
||||
command: npm run e2e
|
||||
config-file: cypress.config.ts
|
||||
-
|
||||
uses: actions/upload-artifact@v4
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,6 +31,7 @@ sandbox.go
|
||||
google-credentials
|
||||
key.json
|
||||
.keys/*
|
||||
load-test/.keys
|
||||
|
||||
# dumps
|
||||
.backups
|
||||
|
@ -339,6 +339,9 @@ OIDC:
|
||||
AuthMethodPrivateKeyJWT: true # ZITADEL_OIDC_AUTHMETHODPRIVATEKEYJWT
|
||||
GrantTypeRefreshToken: true # ZITADEL_OIDC_GRANTTYPEREFRESHTOKEN
|
||||
RequestObjectSupported: true # ZITADEL_OIDC_REQUESTOBJECTSUPPORTED
|
||||
|
||||
# Deprecated: The signing algorithm is determined by the generated keys.
|
||||
# Use the web keys resource to generate keys with different algorithms.
|
||||
SigningKeyAlgorithm: RS256 # ZITADEL_OIDC_SIGNINGKEYALGORITHM
|
||||
# Sets the default values for lifetime and expiration for OIDC
|
||||
# This default can be overwritten in the default instance configuration and for each instance during runtime
|
||||
@ -349,10 +352,10 @@ OIDC:
|
||||
DefaultRefreshTokenIdleExpiration: 720h # ZITADEL_OIDC_DEFAULTREFRESHTOKENIDLEEXPIRATION
|
||||
# 2160h are 90 days, three months
|
||||
DefaultRefreshTokenExpiration: 2160h # ZITADEL_OIDC_DEFAULTREFRESHTOKENEXPIRATION
|
||||
Cache:
|
||||
MaxAge: 12h # ZITADEL_OIDC_CACHE_MAXAGE
|
||||
# 168h is 7 days, one week
|
||||
SharedMaxAge: 168h # ZITADEL_OIDC_CACHE_SHAREDMAXAGE
|
||||
|
||||
# HTTP Cache-Control max-age header value to set on the jwks endpoint.
|
||||
# Only used when the web keys feature is enabled. 0 sets a no-store value.
|
||||
JWKSCacheControlMaxAge: 5m # ZITADEL_OIDC_JWKSCACHECONTROLMAXAGE
|
||||
CustomEndpoints:
|
||||
Auth:
|
||||
Path: /oauth/v2/authorize # ZITADEL_OIDC_CUSTOMENDPOINTS_AUTH_PATH
|
||||
|
@ -45,13 +45,14 @@ import (
|
||||
org_v2 "github.com/zitadel/zitadel/internal/api/grpc/org/v2"
|
||||
org_v2beta "github.com/zitadel/zitadel/internal/api/grpc/org/v2beta"
|
||||
action_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/action/v3alpha"
|
||||
user_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/user/v3alpha"
|
||||
userschema_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/userschema/v3alpha"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/resources/webkey/v3"
|
||||
session_v2 "github.com/zitadel/zitadel/internal/api/grpc/session/v2"
|
||||
session_v2beta "github.com/zitadel/zitadel/internal/api/grpc/session/v2beta"
|
||||
settings_v2 "github.com/zitadel/zitadel/internal/api/grpc/settings/v2"
|
||||
settings_v2beta "github.com/zitadel/zitadel/internal/api/grpc/settings/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/system"
|
||||
user_schema_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/user/schema/v3alpha"
|
||||
user_v2 "github.com/zitadel/zitadel/internal/api/grpc/user/v2"
|
||||
user_v2beta "github.com/zitadel/zitadel/internal/api/grpc/user/v2beta"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
@ -444,7 +445,10 @@ func startAPIs(
|
||||
if err := apis.RegisterService(ctx, action_v3_alpha.CreateServer(config.SystemDefaults, commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, user_schema_v3_alpha.CreateServer(commands, queries)); err != nil {
|
||||
if err := apis.RegisterService(ctx, userschema_v3_alpha.CreateServer(config.SystemDefaults, commands, queries)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, user_v3_alpha.CreateServer(commands, keys.User)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, webkey.CreateServer(commands, queries)); err != nil {
|
||||
|
@ -55,21 +55,21 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^16.2.2",
|
||||
"@angular-eslint/builder": "16.2.0",
|
||||
"@angular-eslint/eslint-plugin": "16.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "16.2.0",
|
||||
"@angular-eslint/builder": "18.3.0",
|
||||
"@angular-eslint/eslint-plugin": "18.0.0",
|
||||
"@angular-eslint/eslint-plugin-template": "18.0.0",
|
||||
"@angular-eslint/schematics": "16.2.0",
|
||||
"@angular-eslint/template-parser": "16.2.0",
|
||||
"@angular-eslint/template-parser": "18.3.0",
|
||||
"@angular/cli": "^16.2.14",
|
||||
"@angular/compiler-cli": "^16.2.5",
|
||||
"@angular/language-service": "^16.2.5",
|
||||
"@bufbuild/buf": "^1.34.0",
|
||||
"@angular/language-service": "^18.2.2",
|
||||
"@bufbuild/buf": "^1.39.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/google-protobuf": "^3.15.3",
|
||||
"@types/jasmine": "~5.1.4",
|
||||
"@types/jasminewd2": "~2.0.13",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
"@types/node": "^20.7.0",
|
||||
"@types/node": "^22.5.2",
|
||||
"@types/opentype.js": "^1.3.8",
|
||||
"@types/qrcode": "^1.5.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
@ -85,7 +85,7 @@
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.1.0",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"prettier-plugin-organize-imports": "^4.0.0",
|
||||
"protractor": "~7.0.0",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
|
@ -168,9 +168,11 @@
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<a class="custom-link" *ngIf="customLink && customLinkText" href="{{ customLink }}" mat-stroked-button target="_blank">
|
||||
{{ customLinkText }}
|
||||
</a>
|
||||
<ng-container *ngIf="authService.privacypolicy | async as pP">
|
||||
<a class="custom-link" *ngIf="pP.customLink" href="{{ pP.customLink }}" mat-stroked-button target="_blank">
|
||||
{{ pP.customLinkText }}
|
||||
</a>
|
||||
</ng-container>
|
||||
|
||||
<a class="doc-link" *ngIf="docsLink" href="{{ docsLink }}" mat-stroked-button target="_blank">
|
||||
{{ 'MENU.DOCUMENTATION' | translate }}
|
||||
|
@ -9,7 +9,6 @@ import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.s
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ActionKeysType } from '../action-keys/action-keys.component';
|
||||
import { GetPrivacyPolicyResponse } from 'src/app/proto/generated/zitadel/management_pb';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-header',
|
||||
@ -32,8 +31,6 @@ export class HeaderComponent implements OnDestroy {
|
||||
public BreadcrumbType: any = BreadcrumbType;
|
||||
public ActionKeysType: any = ActionKeysType;
|
||||
public docsLink = 'https://zitadel.com/docs';
|
||||
public customLink = '';
|
||||
public customLinkText = '';
|
||||
|
||||
public positions: ConnectedPosition[] = [
|
||||
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
|
||||
@ -50,25 +47,7 @@ export class HeaderComponent implements OnDestroy {
|
||||
public mgmtService: ManagementService,
|
||||
public breadcrumbService: BreadcrumbService,
|
||||
public router: Router,
|
||||
) {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
public async loadData(): Promise<any> {
|
||||
const getData = (): Promise<GetPrivacyPolicyResponse.AsObject> => {
|
||||
return this.mgmtService.getPrivacyPolicy();
|
||||
};
|
||||
|
||||
getData()
|
||||
.then((resp) => {
|
||||
if (resp.policy) {
|
||||
this.docsLink = resp.policy.docsLink;
|
||||
this.customLink = resp.policy.customLink;
|
||||
this.customLinkText = resp.policy.customLinkText;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
) {}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
InitPasswordDoneScreenText,
|
||||
InitPasswordScreenText,
|
||||
LinkingUserDoneScreenText,
|
||||
LinkingUserPromptScreenText,
|
||||
LoginScreenText,
|
||||
LogoutDoneScreenText,
|
||||
MFAProvidersText,
|
||||
@ -377,12 +376,5 @@ export function mapRequestValues(map: Partial<Map>, req: Req): Req {
|
||||
r34.setUsernameLabel(map.externalRegistrationUserOverviewText?.usernameLabel ?? '');
|
||||
req.setExternalRegistrationUserOverviewText(r34);
|
||||
|
||||
const r35 = new LinkingUserPromptScreenText();
|
||||
r35.setTitle(map.linkingUserPromptText?.title ?? '');
|
||||
r35.setDescription(map.linkingUserPromptText?.description ?? '');
|
||||
r35.setLinkButtonText(map.linkingUserPromptText?.linkButtonText ?? '');
|
||||
r35.setOtherButtonText(map.linkingUserPromptText?.otherButtonText ?? '');
|
||||
req.setLinkingUserPromptText(r35);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ const KeyNamesArray = [
|
||||
'initPasswordText',
|
||||
'initializeDoneText',
|
||||
'initializeUserText',
|
||||
'linkingUserPromptText',
|
||||
'linkingUserDoneText',
|
||||
'loginText',
|
||||
'logoutText',
|
||||
|
@ -5,7 +5,7 @@
|
||||
<mat-spinner diameter="30" *ngIf="smsProvidersLoading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div class="sms-providers">
|
||||
<div class="sms-providers" *ngIf="!smsProvidersLoading">
|
||||
<cnsl-card class="sms-card" [nomargin]="true">
|
||||
<div class="sms-provider">
|
||||
<h4 class="title">Twilio</h4>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<cnsl-sidenav
|
||||
*ngIf="currentSetting"
|
||||
[title]="title"
|
||||
[description]="description"
|
||||
[indented]="true"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
|
||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||
import { SidenavSetting } from '../sidenav/sidenav.component';
|
||||
@ -8,23 +8,27 @@ import { SidenavSetting } from '../sidenav/sidenav.component';
|
||||
templateUrl: './settings-list.component.html',
|
||||
styleUrls: ['./settings-list.component.scss'],
|
||||
})
|
||||
export class SettingsListComponent implements OnChanges {
|
||||
export class SettingsListComponent implements OnChanges, OnInit {
|
||||
@Input() public title: string = '';
|
||||
@Input() public description: string = '';
|
||||
@Input() public serviceType!: PolicyComponentServiceType;
|
||||
@Input() public selectedId: string = '';
|
||||
@Input() public selectedId: string | undefined = undefined;
|
||||
@Input() public settingsList: SidenavSetting[] = [];
|
||||
public currentSetting: string | undefined = '';
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
constructor() {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['selectedId']?.currentValue) {
|
||||
if (this.settingsList && this.settingsList.length && changes['selectedId']?.currentValue) {
|
||||
this.currentSetting =
|
||||
this.settingsList && this.settingsList.find((l) => l.id === changes['selectedId'].currentValue)
|
||||
? changes['selectedId'].currentValue
|
||||
: '';
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.currentSetting) {
|
||||
this.currentSetting = this.settingsList ? this.settingsList[0].id : '';
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
<p *ngIf="description" class="cnsl-secondary-text">{{ description }}</p>
|
||||
|
||||
<button
|
||||
*ngIf="currentSetting !== undefined"
|
||||
(click)="value = undefined"
|
||||
*ngIf="currentSetting"
|
||||
(click)="value = ''"
|
||||
class="sidenav-setting-list-element mob-only"
|
||||
[ngClass]="{ active: true }"
|
||||
>
|
||||
@ -18,7 +18,7 @@
|
||||
<ng-container>
|
||||
<span
|
||||
class="sidenav-setting-group hide-on-mobile"
|
||||
[ngClass]="{ show: currentSetting === undefined }"
|
||||
[ngClass]="{ show: !currentSetting }"
|
||||
*ngIf="
|
||||
(setting.groupI18nKey && i > 0 && setting.groupI18nKey !== settingsList[i - 1].groupI18nKey) ||
|
||||
(i === 0 && setting.groupI18nKey)
|
||||
@ -29,7 +29,7 @@
|
||||
<button
|
||||
(click)="value = setting.id"
|
||||
class="sidenav-setting-list-element hide-on-mobile"
|
||||
[ngClass]="{ active: currentSetting === setting.id, show: currentSetting === undefined }"
|
||||
[ngClass]="{ active: currentSetting === setting.id, show: !currentSetting }"
|
||||
[attr.data-e2e]="'sidenav-element-' + setting.id"
|
||||
>
|
||||
<span>{{ setting.i18nKey | translate }}</span>
|
||||
@ -40,7 +40,7 @@
|
||||
<button
|
||||
(click)="value = setting.id"
|
||||
class="sidenav-setting-list-element hide-on-mobile"
|
||||
[ngClass]="{ active: currentSetting === setting.id, show: currentSetting === undefined }"
|
||||
[ngClass]="{ active: currentSetting === setting.id, show: !currentSetting }"
|
||||
>
|
||||
<span>{{ setting.i18nKey | translate }}</span>
|
||||
</button>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@ -19,9 +19,9 @@ export interface SidenavSetting {
|
||||
selector: 'cnsl-sidenav',
|
||||
templateUrl: './sidenav.component.html',
|
||||
styleUrls: ['./sidenav.component.scss'],
|
||||
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: SidenavComponent, multi: true }],
|
||||
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SidenavComponent), multi: true }],
|
||||
})
|
||||
export class SidenavComponent implements ControlValueAccessor, OnInit {
|
||||
export class SidenavComponent implements ControlValueAccessor {
|
||||
@Input() public title: string = '';
|
||||
@Input() public description: string = '';
|
||||
@Input() public indented: boolean = false;
|
||||
@ -35,12 +35,6 @@ export class SidenavComponent implements ControlValueAccessor, OnInit {
|
||||
private route: ActivatedRoute,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.value) {
|
||||
this.value = this.settingsList[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
private onChange = (current: string | undefined) => {};
|
||||
private onTouch = (current: string | undefined) => {};
|
||||
|
||||
@ -51,7 +45,7 @@ export class SidenavComponent implements ControlValueAccessor, OnInit {
|
||||
set value(setting: string | undefined) {
|
||||
this.currentSetting = setting;
|
||||
|
||||
if (setting || setting === undefined) {
|
||||
if (setting || setting === undefined || setting === '') {
|
||||
this.onChange(setting);
|
||||
this.onTouch(setting);
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export class OwnedProjectDetailComponent implements OnInit {
|
||||
public refreshChanges$: EventEmitter<void> = new EventEmitter();
|
||||
|
||||
public settingsList: SidenavSetting[] = [GENERAL, ROLES, PROJECTGRANTS, GRANTS];
|
||||
public currentSetting: string | undefined = '';
|
||||
public currentSetting: string = '';
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
@ -72,12 +72,11 @@ export class OwnedProjectDetailComponent implements OnInit {
|
||||
private router: Router,
|
||||
private breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.currentSetting = 'general';
|
||||
route.queryParams.pipe(take(1)).subscribe((params: Params) => {
|
||||
const { id } = params;
|
||||
if (id) {
|
||||
this.currentSetting = id;
|
||||
} else {
|
||||
this.currentSetting = 'general';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1627,7 +1627,6 @@
|
||||
"initPasswordText": "Инициализиране на парола",
|
||||
"initializeDoneText": "Инициализирането на потребителя е готово",
|
||||
"initializeUserText": "Инициализирайте потребителя",
|
||||
"linkingUserPromptText": "Потребителският промпт за свързване",
|
||||
"linkingUserDoneText": "Свързването на потребителя е готово",
|
||||
"loginText": "Влизам",
|
||||
"logoutText": "Излез от профила си",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Inicializace hesla",
|
||||
"initializeDoneText": "Inicializace uživatele dokončena",
|
||||
"initializeUserText": "Inicializace uživatele",
|
||||
"linkingUserPromptText": "Uživatelský propojovací text",
|
||||
"linkingUserDoneText": "Propojení uživatele dokončeno",
|
||||
"loginText": "Přihlášení",
|
||||
"logoutText": "Odhlášení",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Passwort Initialisierung",
|
||||
"initializeDoneText": "Benutzereinrichtung erfolgreich",
|
||||
"initializeUserText": "Benutzereinrichtung",
|
||||
"linkingUserPromptText": "Aufforderung zur Benutzerverlinkung",
|
||||
"linkingUserDoneText": "Benutzerverlinkung erfolgreich",
|
||||
"loginText": "Anmelden",
|
||||
"logoutText": "Abmelden",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Initialize password",
|
||||
"initializeDoneText": "Initialize user done",
|
||||
"initializeUserText": "Initialize user",
|
||||
"linkingUserPromptText": "Linking user prompt",
|
||||
"linkingUserDoneText": "Linking user done",
|
||||
"loginText": "Login",
|
||||
"logoutText": "Logout",
|
||||
|
@ -1629,7 +1629,6 @@
|
||||
"initPasswordText": "Inicializar contraseña",
|
||||
"initializeDoneText": "Inicializar usuario, hecho",
|
||||
"initializeUserText": "Inicializar usuario",
|
||||
"linkingUserPromptText": "Mensaje de enlace de usuario",
|
||||
"linkingUserDoneText": "Vinculación de usuario, hecho",
|
||||
"loginText": "Iniciar sesión",
|
||||
"logoutText": "Cerrar sesión",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Initialiser le mot de passe",
|
||||
"initializeDoneText": "Initialiser l'utilisateur terminé",
|
||||
"initializeUserText": "Initialiser l'utilisateur",
|
||||
"linkingUserPromptText": "Message de liaison utilisateur",
|
||||
"linkingUserDoneText": "Lier l'utilisateur fait",
|
||||
"loginText": "Connexion",
|
||||
"logoutText": "Déconnexion",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Inizializzazione della password",
|
||||
"initializeDoneText": "Inizializzazione utente finita",
|
||||
"initializeUserText": "Inizializzazione utente",
|
||||
"linkingUserPromptText": "Testo di promemoria per collegare l'utente",
|
||||
"linkingUserDoneText": "Collegamento dell'utente finito",
|
||||
"loginText": "Accesso",
|
||||
"logoutText": "Logout",
|
||||
|
@ -1624,7 +1624,6 @@
|
||||
"initPasswordText": "パスワードを初期化する",
|
||||
"initializeDoneText": "ユーザーの初期化が完了しました",
|
||||
"initializeUserText": "ユーザーを初期化する",
|
||||
"linkingUserPromptText": "ユーザーのリンクプロンプト",
|
||||
"linkingUserDoneText": "ユーザーのリンクが完了しました",
|
||||
"loginText": "ログイン",
|
||||
"logoutText": "ログアウト",
|
||||
|
@ -1629,7 +1629,6 @@
|
||||
"initPasswordText": "Иницијализација на лозинка",
|
||||
"initializeDoneText": "Иницијализацијата на корисникот е завршена",
|
||||
"initializeUserText": "Иницијализација на корисник",
|
||||
"linkingUserPromptText": "Поврзување на кориснички промпт",
|
||||
"linkingUserDoneText": "Поврзувањето на корисникот е завршено",
|
||||
"loginText": "Најава",
|
||||
"logoutText": "Одјава",
|
||||
|
@ -1628,7 +1628,6 @@
|
||||
"initPasswordText": "Initialiseer wachtwoord",
|
||||
"initializeDoneText": "Gebruiker initialisatie voltooid",
|
||||
"initializeUserText": "Initialiseer gebruiker",
|
||||
"linkingUserPromptText": "Gebruiker koppelingsprompt",
|
||||
"linkingUserDoneText": "Gebruiker koppeling voltooid",
|
||||
"loginText": "Login",
|
||||
"logoutText": "Uitloggen",
|
||||
|
@ -1627,7 +1627,6 @@
|
||||
"initPasswordText": "Inicjalizacja hasła",
|
||||
"initializeDoneText": "Inicjalizacja użytkownika zakończona",
|
||||
"initializeUserText": "Inicjalizacja użytkownika",
|
||||
"linkingUserPromptText": "Komunikat o łączeniu użytkowników",
|
||||
"linkingUserDoneText": "Łączenie użytkownika zakończone",
|
||||
"loginText": "Zaloguj się",
|
||||
"logoutText": "Wyloguj się",
|
||||
|
@ -1629,7 +1629,6 @@
|
||||
"initPasswordText": "Inicialização de senha",
|
||||
"initializeDoneText": "Inicialização de usuário concluída",
|
||||
"initializeUserText": "Inicializaçãode usuário",
|
||||
"linkingUserPromptText": "Prompt de usuário para vinculação",
|
||||
"linkingUserDoneText": "Vinculação de usuário concluída",
|
||||
"loginText": "Login",
|
||||
"logoutText": "Logout",
|
||||
|
@ -1693,7 +1693,6 @@
|
||||
"initPasswordText": "Инициализировать пароль",
|
||||
"initializeDoneText": "Инициализация пользователя выполнена",
|
||||
"initializeUserText": "Инициализировать пользователя",
|
||||
"linkingUserPromptText": "Текст приглашения к привязке пользователя",
|
||||
"linkingUserDoneText": "Привязка пользователя выполнена",
|
||||
"loginText": "Вход",
|
||||
"logoutText": "Выход",
|
||||
|
@ -1632,7 +1632,6 @@
|
||||
"initPasswordText": "Initiera lösenord",
|
||||
"initializeDoneText": "Initiera användare klart",
|
||||
"initializeUserText": "Initiera användare",
|
||||
"linkingUserPromptText": "Länka användarprompt",
|
||||
"linkingUserDoneText": "Länka användare klart",
|
||||
"loginText": "Inloggning",
|
||||
"logoutText": "Utloggning",
|
||||
|
@ -1627,7 +1627,6 @@
|
||||
"initPasswordText": "初始化密码",
|
||||
"initializeDoneText": "初始化用户完成",
|
||||
"initializeUserText": "初始化用户",
|
||||
"linkingUserPromptText": "用户链接提示",
|
||||
"linkingUserDoneText": "链接用户完成",
|
||||
"loginText": "登录",
|
||||
"logoutText": "登出",
|
||||
|
@ -129,19 +129,26 @@
|
||||
ora "5.4.1"
|
||||
rxjs "7.8.1"
|
||||
|
||||
"@angular-eslint/builder@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/builder/-/builder-16.2.0.tgz#ae5ddc2c658c54918186efba55a6cebb801880c0"
|
||||
integrity sha512-SZjXOi3YIjuX2CocuRsR2QH6k1ca9lRO6IMm0YIYMmBPFCRP2KFHkL6aQnXM6DSaymQNN2TXfpuvUd45NxhU1w==
|
||||
dependencies:
|
||||
"@nx/devkit" "16.5.1"
|
||||
nx "16.5.1"
|
||||
"@angular-eslint/builder@18.3.0":
|
||||
version "18.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/builder/-/builder-18.3.0.tgz#e4a62f45c1d2c37572be4018ec2eefd515d1aacc"
|
||||
integrity sha512-httEQyqyBw3+0CRtAa7muFxHrauRfkEfk/jmrh5fn2Eiu+I53hAqFPgrwVi1V6AP/kj2zbAiWhd5xM3pMJdoRQ==
|
||||
|
||||
"@angular-eslint/bundled-angular-compiler@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-16.2.0.tgz#09d0637d738850a2c6f0523f19632e992f790102"
|
||||
integrity sha512-ct9orDYxkMl2+uvM7UBfgV28Dq57V4dEs+Drh7cD673JIMa6sXbgmd0QEtm8W3cmyK/jcTzmuoufxbH7hOxd6g==
|
||||
|
||||
"@angular-eslint/bundled-angular-compiler@18.0.0":
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.0.0.tgz#b95769124ccbfed6a313e0b0b56c4c7fd90eef30"
|
||||
integrity sha512-c5XNfpWN6vfMoZpnLLeras7nUIVI10ofJu3W3s1s1NpCjP67kY84SPYRJIND1LemVewMQ+mhnP4xJnqvJxC1tA==
|
||||
|
||||
"@angular-eslint/bundled-angular-compiler@18.3.0":
|
||||
version "18.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.0.tgz#086bf5d529e60a864bbcf3d448ccb9544bfd9b86"
|
||||
integrity sha512-v/59FxUKnMzymVce99gV43huxoqXWMb85aKvzlNvLN+ScDu6ZE4YMiTQNpfapVL2lkxhs0uwB3jH17EYd5TcsA==
|
||||
|
||||
"@angular-eslint/eslint-plugin-template@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-16.2.0.tgz#5d1dd0f450020c9bc8d9cbd5fcbf173b15ff3bd3"
|
||||
@ -154,6 +161,17 @@
|
||||
aria-query "5.3.0"
|
||||
axobject-query "3.2.1"
|
||||
|
||||
"@angular-eslint/eslint-plugin-template@18.0.0":
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.0.0.tgz#d355504af560487b3177fc8ecf62fee292a8e29b"
|
||||
integrity sha512-KN32zW5eutRLumjJNGM77pZ4dpQe/PlffU2fGGVagHSDRrjaEqBmJ/khecUHjz3+VxYLbVWBM2skfb5jC4Lr2g==
|
||||
dependencies:
|
||||
"@angular-eslint/bundled-angular-compiler" "18.0.0"
|
||||
"@angular-eslint/utils" "18.0.0"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.20"
|
||||
aria-query "5.3.0"
|
||||
axobject-query "4.0.0"
|
||||
|
||||
"@angular-eslint/eslint-plugin@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin/-/eslint-plugin-16.2.0.tgz#2d61d087d208f347c9c472ecd9b0eee1fae1b21b"
|
||||
@ -162,6 +180,15 @@
|
||||
"@angular-eslint/utils" "16.2.0"
|
||||
"@typescript-eslint/utils" "5.62.0"
|
||||
|
||||
"@angular-eslint/eslint-plugin@18.0.0":
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/eslint-plugin/-/eslint-plugin-18.0.0.tgz#67982243625f66a8fb0141d34df6c44855bd6977"
|
||||
integrity sha512-XhsIR28HiFOg3qbyjr0ZFBvOeFSXowbriFn8pAuiUjYoLJEtNZzPA1Ih/J0Ky5ZXYwcSJbZRQdNR/q1INQEFqA==
|
||||
dependencies:
|
||||
"@angular-eslint/bundled-angular-compiler" "18.0.0"
|
||||
"@angular-eslint/utils" "18.0.0"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.20"
|
||||
|
||||
"@angular-eslint/schematics@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/schematics/-/schematics-16.2.0.tgz#587321a0813beede1ec7fe50413ca089bb4f6bb7"
|
||||
@ -175,13 +202,13 @@
|
||||
strip-json-comments "3.1.1"
|
||||
tmp "0.2.1"
|
||||
|
||||
"@angular-eslint/template-parser@16.2.0":
|
||||
version "16.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/template-parser/-/template-parser-16.2.0.tgz#eccd1a2424b001a585107ec4db8eda726bdc9a6d"
|
||||
integrity sha512-v2jVKTy2wN7iM9nHpBkxLn2wfL8jSl4IlPrXThIqj8No2VHtpLQZPKuXbGPUXQX05VS2Mj5feScQ36ZVGS8Rbw==
|
||||
"@angular-eslint/template-parser@18.3.0":
|
||||
version "18.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/template-parser/-/template-parser-18.3.0.tgz#c64e7e5a5dba9599d23fb3a0ac2e1aef101eeeec"
|
||||
integrity sha512-1mUquqcnugI4qsoxcYZKZ6WMi6RPelDcJZg2YqGyuaIuhWmi3ZqJZLErSSpjP60+TbYZu7wM8Kchqa1bwJtEaQ==
|
||||
dependencies:
|
||||
"@angular-eslint/bundled-angular-compiler" "16.2.0"
|
||||
eslint-scope "^7.0.0"
|
||||
"@angular-eslint/bundled-angular-compiler" "18.3.0"
|
||||
eslint-scope "^8.0.2"
|
||||
|
||||
"@angular-eslint/utils@16.2.0":
|
||||
version "16.2.0"
|
||||
@ -191,6 +218,14 @@
|
||||
"@angular-eslint/bundled-angular-compiler" "16.2.0"
|
||||
"@typescript-eslint/utils" "5.62.0"
|
||||
|
||||
"@angular-eslint/utils@18.0.0":
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular-eslint/utils/-/utils-18.0.0.tgz#1ddedf84d3ff5275387d35b22a974f54f5eb33f2"
|
||||
integrity sha512-ygOlsC5HrknbI8Ah5pa6tGtrpxB0W4UqzZG9Ii7whoWs7OjkBTIbeNy/qaWv1e45MR2/Ytd5BSWK17w0Poyz8w==
|
||||
dependencies:
|
||||
"@angular-eslint/bundled-angular-compiler" "18.0.0"
|
||||
"@typescript-eslint/utils" "8.0.0-alpha.20"
|
||||
|
||||
"@angular/animations@^16.2.5":
|
||||
version "16.2.12"
|
||||
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-16.2.12.tgz#27744d8176e09e70e0f6d837c3abcfcee843a936"
|
||||
@ -283,10 +318,10 @@
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@angular/language-service@^16.2.5":
|
||||
version "16.2.12"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-16.2.12.tgz#e81d9667ec96eac214b0dd54275bdfb835db3f3f"
|
||||
integrity sha512-sZwB+ZEjChx9EYcqPaS4OnhC/q5RcedZjIdM9mCxuU/MtseURRYRI/8Hnm1RHo9qyc5PmsQpg7p9Vp/5hXLUjw==
|
||||
"@angular/language-service@^18.2.2":
|
||||
version "18.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.2.tgz#8a6b3f224871cb4b1dd5d76a43a1c3884d14aa62"
|
||||
integrity sha512-aROQNQeLf+o+F5OVvE/9BUe/Tpv8pjzmrZlogBbic5cb4IqSNhR4RjxbgIyXBO/6bhLCZwqfmMqRbW2J2xqMkg==
|
||||
|
||||
"@angular/material-moment-adapter@^16.2.4":
|
||||
version "16.2.14"
|
||||
@ -1427,47 +1462,47 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bufbuild/buf-darwin-arm64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.35.1.tgz#7d7567180df771e94cc95267276da7966be7b90a"
|
||||
integrity sha512-Yy+sk+8sg3LDvMSZLGUIoMCkZajkQSZkdxO96mpqJagKlEYPLGTtakVFCVNX9KgK/sv1bd9sU55iMGXE3+eIYw==
|
||||
"@bufbuild/buf-darwin-arm64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.39.0.tgz#0ab8453dc7fc7694e5bd39c69d934edc51b81c81"
|
||||
integrity sha512-Ptl0uAGssLxQTzoZhGwv1FFTbzUfcstIpEwMhN+XrwiuqsSxOg9eq/n3yXoci5VJsHokjDUHnWkR3y+j5P/5KA==
|
||||
|
||||
"@bufbuild/buf-darwin-x64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.35.1.tgz#05b6dc00944aa2150acf67f4c6f1d8592312f0de"
|
||||
integrity sha512-LcscoNTCHFeb5y9sitw4w6HWZtJ4Ja/MDBCUU9A8/OGHJSESV0JjhbvVHGNOIsKUbPq5p/SVjYA/Ab/wlmmpaA==
|
||||
"@bufbuild/buf-darwin-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.39.0.tgz#9c9a211c8039b8cb89b45bf44f338edf82d5e506"
|
||||
integrity sha512-XNCuy9sjQwVJ4NIZqxaTIyzUtlyquSkp/Uuoh5W5thJ3nzZ5RSgvXKF5iXHhZmesrfRGApktwoCx5Am8runsfQ==
|
||||
|
||||
"@bufbuild/buf-linux-aarch64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.35.1.tgz#fb26dbe860229759c224a3c91d5e77dab1874113"
|
||||
integrity sha512-bPeiSURl8WFxCdawtJjAjUOMqknVTw763NLIDcbYSH1/wTiUbM5QeXCORRlHKXtMGM89SYU5AatcY9UhQ+sn9g==
|
||||
"@bufbuild/buf-linux-aarch64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.39.0.tgz#9778732efbdbbfe02ec821017cc2392ce4a0153f"
|
||||
integrity sha512-Am+hrw94awp/eY027ROXwRQBuwAzOpQ/4zI4dgmgsyhzeWZ8w1LWC8z2SSr8T2cqd0cm52KxtoWMW+B3b2qzbw==
|
||||
|
||||
"@bufbuild/buf-linux-x64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.35.1.tgz#552399c5f42dbbef21968771e6364306c4667313"
|
||||
integrity sha512-n6ziazYjNH9H1JjHiacGi20rIyZuKnsHjF8qWisO8KGajhnS/7tpq0VzYdorqqWyJ1TcnLBWHj+dWYuGay9Nag==
|
||||
"@bufbuild/buf-linux-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.39.0.tgz#d7ca62c4f506c60011f5a97ca2e8683aa26693b0"
|
||||
integrity sha512-JXVkHoMrTvmpseqdoQPJJ6MRV7/vlloYtvXHHACEzVytYjljOYCNoVET/E5gLBco/edeXFMNc40cCi1KgL3rSw==
|
||||
|
||||
"@bufbuild/buf-win32-arm64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.35.1.tgz#efd0a6a2159a135173becfbe362651a4a4e1dd4d"
|
||||
integrity sha512-3B65+iA1i/LDjJBseEpAvrkEI7VJqrvW39PyYVkIXSHHT917O+n95g74pn38A0XkggN5lEibLEkipBMDUfwMew==
|
||||
"@bufbuild/buf-win32-arm64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.39.0.tgz#efdaf1eca30445f04124c6d829a46a676e6b1dc3"
|
||||
integrity sha512-akdGW02mo04wbLfjNMBQqxC4mPQ/L/vTU8/o79I67GSxyFYt7bKifvYIYhAA39C2gibHyB7ZLmoeRPbaU8wbYA==
|
||||
|
||||
"@bufbuild/buf-win32-x64@1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.35.1.tgz#24cd639b4b692233c4ba6004263933b433a2ff13"
|
||||
integrity sha512-iafrcs+1FMlD+3ZjI1kVBHGOluT6YcoAUETrGMbQjRha6dL5s2Ldr0G7zCKLIT13yEKG5QTyP8z8gVEpk8C8wg==
|
||||
"@bufbuild/buf-win32-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.39.0.tgz#09f2b0290818d826847689d6149f8fb0def4ac4b"
|
||||
integrity sha512-jos08UMg9iUZsGjPrNpLXP+FNk6q6GizO+bjee/GcI0kSijIzXYMg14goQr0TKlvqs/+IRAM5vZIokQBYlAENQ==
|
||||
|
||||
"@bufbuild/buf@^1.34.0":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.35.1.tgz#46a700b94b463919f21313962e539f63448c7d90"
|
||||
integrity sha512-POtbb4wRhvgCmmClnuaQTpkHL4ukhFItuS/AaD7QDY0kamn4ExNJz4XlHG5jeJODaQ1Wq3f9qn7UIgUr6CUODw==
|
||||
"@bufbuild/buf@^1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.39.0.tgz#65884f55d072b93122959c92b389c1d7d8ab510b"
|
||||
integrity sha512-lm7xb9pc7X04rRjCQ69o9byAAZ7/dsUQGoH+iJ9uBSXQWiwQ1Ts8gneBnuUVsAH2vdW73NFBpmNQGE9XtFauVQ==
|
||||
optionalDependencies:
|
||||
"@bufbuild/buf-darwin-arm64" "1.35.1"
|
||||
"@bufbuild/buf-darwin-x64" "1.35.1"
|
||||
"@bufbuild/buf-linux-aarch64" "1.35.1"
|
||||
"@bufbuild/buf-linux-x64" "1.35.1"
|
||||
"@bufbuild/buf-win32-arm64" "1.35.1"
|
||||
"@bufbuild/buf-win32-x64" "1.35.1"
|
||||
"@bufbuild/buf-darwin-arm64" "1.39.0"
|
||||
"@bufbuild/buf-darwin-x64" "1.39.0"
|
||||
"@bufbuild/buf-linux-aarch64" "1.39.0"
|
||||
"@bufbuild/buf-linux-x64" "1.39.0"
|
||||
"@bufbuild/buf-win32-arm64" "1.39.0"
|
||||
"@bufbuild/buf-win32-x64" "1.39.0"
|
||||
|
||||
"@colors/colors@1.5.0":
|
||||
version "1.5.0"
|
||||
@ -1712,7 +1747,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
|
||||
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0":
|
||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
|
||||
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
|
||||
@ -3063,19 +3098,12 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0":
|
||||
version "22.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.0.0.tgz#04862a2a71e62264426083abe1e27e87cac05a30"
|
||||
integrity sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==
|
||||
"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0", "@types/node@^22.5.2":
|
||||
version "22.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793"
|
||||
integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==
|
||||
dependencies:
|
||||
undici-types "~6.11.1"
|
||||
|
||||
"@types/node@^20.7.0":
|
||||
version "20.14.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.13.tgz#bf4fe8959ae1c43bc284de78bd6c01730933736b"
|
||||
integrity sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w==
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
undici-types "~6.19.2"
|
||||
|
||||
"@types/normalize-package-data@^2.4.1":
|
||||
version "2.4.4"
|
||||
@ -3208,6 +3236,14 @@
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
||||
|
||||
"@typescript-eslint/scope-manager@8.0.0-alpha.20":
|
||||
version "8.0.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.20.tgz#2f953a8f62e87d65b7a5d19800f7c996e0fe8b11"
|
||||
integrity sha512-+Ncj0Q6DT8ZHYNp8h5RndW4Siv52kiPpHEz/i8Sj2rh2y8ZCc5pKSHSslk+eZi0Bdj+/+swNOmDNcL2CrlaEnA==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.20"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.20"
|
||||
|
||||
"@typescript-eslint/type-utils@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a"
|
||||
@ -3223,6 +3259,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
|
||||
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
|
||||
|
||||
"@typescript-eslint/types@8.0.0-alpha.20":
|
||||
version "8.0.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.0.0-alpha.20.tgz#f6d6ed7789178934fcdc67a0796191580f505730"
|
||||
integrity sha512-xpU1rMQfnnNZxpHN6YUfr18sGOMcpC9hvt54fupcU6N1qMCagEtkRt1U15x086oJAgAITJGa67454ffAoCxv/w==
|
||||
|
||||
"@typescript-eslint/typescript-estree@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
|
||||
@ -3236,6 +3277,20 @@
|
||||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@8.0.0-alpha.20":
|
||||
version "8.0.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.20.tgz#f495288215150f64af97896f2c1a8cf44197d09c"
|
||||
integrity sha512-VQ8Mf8upDCuf0uMTjX/Pdw3gvCZomkG43nuThUuzhK3YFwFmIDTqx0ZWSsYJkVGfll0WrXgIua+rKSP/n6NBWw==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.20"
|
||||
"@typescript-eslint/visitor-keys" "8.0.0-alpha.20"
|
||||
debug "^4.3.4"
|
||||
globby "^11.1.0"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^1.3.0"
|
||||
|
||||
"@typescript-eslint/utils@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
|
||||
@ -3250,6 +3305,16 @@
|
||||
eslint-scope "^5.1.1"
|
||||
semver "^7.3.7"
|
||||
|
||||
"@typescript-eslint/utils@8.0.0-alpha.20":
|
||||
version "8.0.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.0.0-alpha.20.tgz#f8e7b6d282714e9e34e891eab2daf8d9b76db5a3"
|
||||
integrity sha512-0aMhjDTvIrkGkHqyM0ZByAwR8BV1f2HhKdYyjtxko8S/Ca4PGjOIjub6VoF+bQwCRxEuV8viNUld78rqm9jqLA==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@typescript-eslint/scope-manager" "8.0.0-alpha.20"
|
||||
"@typescript-eslint/types" "8.0.0-alpha.20"
|
||||
"@typescript-eslint/typescript-estree" "8.0.0-alpha.20"
|
||||
|
||||
"@typescript-eslint/visitor-keys@5.62.0":
|
||||
version "5.62.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
|
||||
@ -3258,6 +3323,14 @@
|
||||
"@typescript-eslint/types" "5.62.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.0.0-alpha.20":
|
||||
version "8.0.0-alpha.20"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.20.tgz#bffce2fa485fd99b071a4a51fec8ed6ad7a8d1a3"
|
||||
integrity sha512-ej06rfct0kalfJgIR8nTR7dF1mgfF83hkylrYas7IAElHfgw4zx99BUGa6VrnHZ1PkxdJBp5PgcO2FmmlOoaRQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.0.0-alpha.20"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@ungap/structured-clone@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
||||
@ -3780,9 +3853,9 @@ aws4@^1.8.0:
|
||||
integrity sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==
|
||||
|
||||
axios@^1.0.0:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
|
||||
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2"
|
||||
integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.6"
|
||||
form-data "^4.0.0"
|
||||
@ -3802,6 +3875,13 @@ axobject-query@3.2.1:
|
||||
dependencies:
|
||||
dequal "^2.0.3"
|
||||
|
||||
axobject-query@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.0.0.tgz#04a4c90dce33cc5d606c76d6216e3b250ff70dab"
|
||||
integrity sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==
|
||||
dependencies:
|
||||
dequal "^2.0.3"
|
||||
|
||||
babel-loader@9.1.3:
|
||||
version "9.1.3"
|
||||
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-9.1.3.tgz#3d0e01b4e69760cc694ee306fe16d358aa1c6f9a"
|
||||
@ -5042,7 +5122,7 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.0.0, eslint-scope@^7.2.2:
|
||||
eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
|
||||
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
|
||||
@ -5050,6 +5130,14 @@ eslint-scope@^7.0.0, eslint-scope@^7.2.2:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-scope@^8.0.2:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94"
|
||||
integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
@ -6967,9 +7055,9 @@ methods@~1.1.2:
|
||||
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
|
||||
|
||||
micromatch@^4.0.2, micromatch@^4.0.4:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
|
||||
integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
||||
dependencies:
|
||||
braces "^3.0.3"
|
||||
picomatch "^2.3.1"
|
||||
@ -7910,10 +7998,10 @@ prelude-ls@^1.2.1:
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
prettier-plugin-organize-imports@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e"
|
||||
integrity sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==
|
||||
prettier-plugin-organize-imports@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.0.0.tgz#a69acf024ea3c8eb650c81f664693826ca853534"
|
||||
integrity sha512-vnKSdgv9aOlqKeEFGhf9SCBsTyzDSyScy1k7E0R1Uo4L0cTcOV7c1XQaT7jfXIOc/p08WLBfN2QUQA9zDSZMxA==
|
||||
|
||||
prettier@^3.1.1:
|
||||
version "3.3.3"
|
||||
@ -8506,7 +8594,7 @@ semver@^6.3.0, semver@^6.3.1:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3:
|
||||
semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.6.0:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
@ -9157,6 +9245,11 @@ tree-kill@1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
|
||||
integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
|
||||
|
||||
ts-api-utils@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
|
||||
integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
|
||||
|
||||
tsconfig-paths@^4.1.2:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c"
|
||||
@ -9254,15 +9347,10 @@ ua-parser-js@^0.7.30:
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.38.tgz#f497d8a4dc1fec6e854e5caa4b2f9913422ef054"
|
||||
integrity sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==
|
||||
|
||||
undici-types@~5.26.4:
|
||||
version "5.26.5"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
undici-types@~6.11.1:
|
||||
version "6.11.1"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197"
|
||||
integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==
|
||||
undici-types@~6.19.2:
|
||||
version "6.19.8"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
|
||||
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
||||
|
||||
unicode-canonical-property-names-ecmascript@^2.0.0:
|
||||
version "2.0.0"
|
||||
|
@ -665,6 +665,8 @@ No parameters are needed apart from the user agent cookie, but you can provide t
|
||||
The `post_logout_redirect_uri` will be checked against the previously registered uris of the client provided by the `azp` claim of the `id_token_hint` or the `client_id` parameter.
|
||||
If both parameters are provided, they must be equal.
|
||||
|
||||
If neither an `id_token_hint` nor a `client_id` parameter is provided, the `post_logout_redirect_uri` will be ignored.
|
||||
|
||||
## jwks_uri
|
||||
|
||||
`{your_domain}/oauth/v2/keys`
|
||||
|
@ -85,20 +85,20 @@ https://github.com/zitadel/zitadel-vue/blob/main/src/main.ts
|
||||
The restricted admin view will only be shown if the user is authenticated and has the role "admin" in the apps project in ZITADEL.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/Admin.vue
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/AdminView.vue
|
||||
```
|
||||
|
||||
The restricted login view is shown to all authenticated users.
|
||||
It prints all the information it gets from the token and from the user info endpoint.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/Login.vue
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/LoginView.vue
|
||||
```
|
||||
|
||||
The public no access view is shown to authenticated users who navigate to a page they don't have access to based on their roles.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/NoAccess.vue
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/NoAccessView.vue
|
||||
```
|
||||
|
||||
### Add protected routes to your new pages as well as a Signout link
|
||||
@ -126,4 +126,4 @@ Now that you have enabled authentication, you are ready to call add authorizatio
|
||||
To do this, [refer to the API docs](/apis/introduction) or check out [the ZITADEL Console code on GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
|
||||
|
||||
For more information on how to create an Vue application, you can refer to [Vue](https://vuejs.org/guide/quick-start.html).
|
||||
If you want to learn more about the libraries wrapped by [@zitadel/vue](https://www.npmjs.com/package/@zitadel/vue), [read the docs for vue-oidc-client](https://github.com/soukoku/vue-oidc-client/wiki/V1-Docs).
|
||||
If you want to learn more about the libraries wrapped by [@zitadel/vue](https://www.npmjs.com/package/@zitadel/vue), [read the docs for vue-oidc-client](https://github.com/soukoku/vue-oidc-client/wiki/V1-Docs).
|
||||
|
@ -208,12 +208,12 @@ curl -L -X POST 'https://$CUSTOM-DOMAIN/admin/v1/orgs/_setup' \
|
||||
Detailed description of [Setup Organization](/docs/apis/resources/admin/admin-service-set-up-org#setup-organization)
|
||||
|
||||
If you need to add custom data to either the organization or the user you can use the metadata.
|
||||
Metadata is a key value construct that allows you to store any additional information to the ressources.
|
||||
Metadata is a key value construct that allows you to store any additional information to the resources.
|
||||
The set organization metadata request allows you to add one key value pair to an organization:
|
||||
[Set Organization Metadata](/docs/apis/resources/mgmt/management-service-set-org-metadata)
|
||||
If you have more than one field, you can use the bulk add request:
|
||||
[Bulk Set Organization Metadata](/docs/apis/resources/mgmt/management-service-bulk-set-org-metadata)
|
||||
|
||||
The same requests also exist on the user ressource:
|
||||
The same requests also exist on the user resource:
|
||||
[Set User Metadata](/docs/apis/resources/mgmt/management-service-set-user-metadata)
|
||||
[Bulk Set User Metadata](/docs/apis/resources/mgmt/management-service-bulk-set-user-metadata)
|
||||
|
@ -129,7 +129,7 @@ curl --request POST \
|
||||
"limit": 1000,
|
||||
"event_types": [
|
||||
"user.token.added",
|
||||
"user.refresh.token.added
|
||||
"user.refresh.token.added"
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
@ -54,11 +54,33 @@ Tracing:
|
||||
ZITADEL follows the principles that guide cloud-native and twelve factor applications.
|
||||
Logs are a stream of time-ordered events collected from all running processes.
|
||||
|
||||
ZITADEL processes write the following events to the standard output:
|
||||
[ZITADEL is configurable](#default-zitadel-logging-config) to write the following events to the standard output:
|
||||
|
||||
- Runtime Logs: Define the log level and record format [in the Log configuration section](https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml#L1-L4)
|
||||
- Access Logs: Enable logging all HTTP and gRPC responses from the ZITADEL binary [in the LogStore section](https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml#L366)
|
||||
- Actions Exectution Logs: Actions can emit custom logs at different levels. For example, a log record can be emitted each time a user is created or authenticated. If you don't want to have these logs in STDOUT, you can disable this [in the LogStore section](https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml#L387) .
|
||||
- Runtime Logs: Define the log level and record format in the `Log` configuration section.
|
||||
- Access Logs: Enable logging all HTTP and gRPC responses from the ZITADEL binary by setting `LogStore.Access.Stdout.Enabled` to true.
|
||||
- Actions Execution Logs: Actions can emit custom logs at different levels. For example, a log record can be emitted each time a user is created or authenticated. If you don't want to have these logs in STDOUT, you can disable this by setting `LogStore.Execution.Stdout.Enabled` to true.
|
||||
|
||||
### Default ZITADEL Logging Config
|
||||
|
||||
```yaml
|
||||
Log:
|
||||
Level: info # ZITADEL_LOG_LEVEL
|
||||
Formatter:
|
||||
Format: text # ZITADEL_LOG_FORMATTER_FORMAT
|
||||
|
||||
LogStore:
|
||||
Access:
|
||||
Stdout:
|
||||
# If enabled, all access logs are printed to the binary's standard output
|
||||
Enabled: false # ZITADEL_LOGSTORE_ACCESS_STDOUT_ENABLED
|
||||
Execution:
|
||||
Stdout:
|
||||
# If enabled, all execution logs are printed to the binary's standard output
|
||||
Enabled: true # ZITADEL_LOGSTORE_EXECUTION_STDOUT_ENABLED
|
||||
|
||||
```
|
||||
|
||||
### Why ZITADEL does not write logs to files
|
||||
|
||||
Log file management should not be in each business apps responsibility.
|
||||
Instead, your execution environment should provide tooling for managing logs in a generic way.
|
||||
|
@ -4,13 +4,13 @@ title: Technical Advisory 10011
|
||||
|
||||
## Date and Version
|
||||
|
||||
Version: 2.60.0
|
||||
Version: 2.59.0
|
||||
|
||||
Date: TBD
|
||||
Date: 2024-08-19
|
||||
|
||||
## Description
|
||||
|
||||
Version 2.60.0 allows more combinations in the identity provider options. As of now, **automatic creation** and **automatic linking options** were only considered if the corresponding **allowed option** (account creation / linking allowed) was enabled.
|
||||
Version 2.59.0 allows more combinations in the identity provider options. As of now, **automatic creation** and **automatic linking options** were only considered if the corresponding **allowed option** (account creation / linking allowed) was enabled.
|
||||
|
||||
Starting with this release, this is no longer needed and allows administrators to address cases, where only an **automatic creation** is allowed, but users themselves should not be allowed to **manually** create new accounts using an identity provider or edit the information during the process.
|
||||
Also, allowing users to only link to the proposed existing account is now possible with an enabled **automatic linking option**, while disabling **account linking allowed**.
|
||||
@ -18,7 +18,7 @@ Also, allowing users to only link to the proposed existing account is now possib
|
||||
## Statement
|
||||
|
||||
This change was tracked in the following PR:
|
||||
[feat(idp): provide auto only options](https://github.com/zitadel/zitadel/pull/8420), which was released in Version [2.60.0](https://github.com/zitadel/zitadel/releases/tag/v2.60.0)
|
||||
[feat(idp): provide auto only options](https://github.com/zitadel/zitadel/pull/8420), which was released in Version [2.59.0](https://github.com/zitadel/zitadel/releases/tag/v2.59.0)
|
||||
|
||||
## Mitigation
|
||||
|
||||
|
@ -185,10 +185,10 @@ We understand that these advisories may include breaking changes, and we aim to
|
||||
<td>Identity Provider options: allow "auto" only</td>
|
||||
<td>Breaking Behavior Change</td>
|
||||
<td>
|
||||
Version 2.60.0 allows more combinations in the identity provider options. Due to this there might be unexpected behavior changes.
|
||||
Version 2.59.0 allows more combinations in the identity provider options. Due to this there might be unexpected behavior changes.
|
||||
</td>
|
||||
<td>2.53.0</td>
|
||||
<td>2024-05-28</td>
|
||||
<td>2.59.0</td>
|
||||
<td>2024-08-19</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -317,7 +317,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
user_schema_v3: {
|
||||
specPath: ".artifacts/openapi/zitadel/user/schema/v3alpha/user_schema_service.swagger.json",
|
||||
specPath: ".artifacts/openapi/zitadel/resources/userschema/v3alpha/user_schema_service.swagger.json",
|
||||
outputDir: "docs/apis/resources/user_schema_service_v3",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
@ -325,7 +325,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
user_v3: {
|
||||
specPath: ".artifacts/openapi/zitadel/user/v3alpha/user_service.swagger.json",
|
||||
specPath: ".artifacts/openapi/zitadel/resources/user/v3alpha/user_service.swagger.json",
|
||||
outputDir: "docs/apis/resources/user_service_v3",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
|
@ -4790,9 +4790,9 @@ elkjs@^0.9.0:
|
||||
integrity sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==
|
||||
|
||||
elliptic@^6.5.3, elliptic@^6.5.5:
|
||||
version "6.5.5"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
|
||||
integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
|
||||
version "6.5.7"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b"
|
||||
integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==
|
||||
dependencies:
|
||||
bn.js "^4.11.9"
|
||||
brorand "^1.1.0"
|
||||
|
@ -61,6 +61,7 @@ export default defineConfig({
|
||||
baseUrl: baseUrl(),
|
||||
experimentalRunAllSpecs: true,
|
||||
experimentalOriginDependencies: true,
|
||||
pageLoadTimeout: 180000,
|
||||
setupNodeEvents(on, config) {
|
||||
|
||||
startWebhookEventHandler()
|
||||
|
@ -26,13 +26,16 @@ describe('applications', () => {
|
||||
|
||||
it('add web pkce app', () => {
|
||||
cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
|
||||
cy.get('[formcontrolname="name"]').focus().type(testPKCEAppName);
|
||||
cy.get('[formcontrolname="name"]').focus().should('be.enabled').type(testPKCEAppName);
|
||||
cy.get('[for="WEB"]').click();
|
||||
cy.get('[data-e2e="continue-button-nameandtype"]').click();
|
||||
cy.get('[for="PKCE"]').should('be.visible').click();
|
||||
cy.get('[data-e2e="continue-button-authmethod"]').click();
|
||||
cy.get('[data-e2e="redirect-uris"] input').focus().type('http://localhost:3000/api/auth/callback/zitadel');
|
||||
cy.get('[data-e2e="postlogout-uris"] input').focus().type('http://localhost:3000');
|
||||
cy.get('[data-e2e="redirect-uris"] input')
|
||||
.focus()
|
||||
.should('be.enabled')
|
||||
.type('http://localhost:3000/api/auth/callback/zitadel');
|
||||
cy.get('[data-e2e="postlogout-uris"] input').focus().should('be.enabled').type('http://localhost:3000');
|
||||
cy.get('[data-e2e="continue-button-redirecturis"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.get('[id*=overlay]').should('exist');
|
||||
@ -56,7 +59,7 @@ describe('applications', () => {
|
||||
|
||||
it('add device code app', () => {
|
||||
cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
|
||||
cy.get('[formcontrolname="name"]').focus().type(testDEVICECODEAppName);
|
||||
cy.get('[formcontrolname="name"]').focus().should('be.enabled').type(testDEVICECODEAppName);
|
||||
cy.get('[for="N"]').click();
|
||||
cy.get('[data-e2e="continue-button-nameandtype"]').click();
|
||||
cy.get('[for="DEVICECODE"]').should('be.visible').click();
|
||||
|
@ -28,14 +28,14 @@ describe('humans', () => {
|
||||
it('should add a user', () => {
|
||||
cy.get('[data-e2e="create-user-button"]').should('be.visible').click();
|
||||
cy.url().should('contain', 'users/create');
|
||||
cy.get('[formcontrolname="email"]').type('dummy@dummy.com');
|
||||
cy.get('[formcontrolname="email"]').should('be.enabled').type('dummy@dummy.com');
|
||||
//force needed due to the prefilled username prefix
|
||||
cy.get('[formcontrolname="userName"]').type(user.addName);
|
||||
cy.get('[formcontrolname="firstName"]').type('e2ehumanfirstname');
|
||||
cy.get('[formcontrolname="lastName"]').type('e2ehumanlastname');
|
||||
cy.get('[formcontrolname="userName"]').should('be.enabled').type(user.addName);
|
||||
cy.get('[formcontrolname="firstName"]').should('be.enabled').type('e2ehumanfirstname');
|
||||
cy.get('[formcontrolname="lastName"]').should('be.enabled').type('e2ehumanlastname');
|
||||
cy.get('mat-select[data-cy="country-calling-code"]').click();
|
||||
cy.contains('mat-option', 'Switzerland').scrollIntoView().click();
|
||||
cy.get('[formcontrolname="phone"]').type('123456789');
|
||||
cy.get('[formcontrolname="phone"]').should('be.enabled').type('123456789');
|
||||
cy.get('[data-e2e="create-button"]').click({ force: true });
|
||||
cy.shouldConfirmSuccess();
|
||||
let loginName = user.addName;
|
||||
@ -58,7 +58,7 @@ describe('humans', () => {
|
||||
it('should delete a human user', () => {
|
||||
const rowSelector = `tr:contains(${user.removeName})`;
|
||||
cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type(user.removeName);
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().should('be.enabled').type(user.removeName);
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.shouldNotExist({
|
||||
|
@ -1,3 +1,10 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { Context } from '../../../support/commands';
|
||||
import { ensureOrgExists } from '../../../support/api/orgs';
|
||||
import { activateSMTPProvider, ensureSMTPProviderExists } from '../../../support/api/smtp';
|
||||
import { ensureSMSProviderDoesntExist, ensureSMSProviderExists } from '../../../support/api/sms';
|
||||
|
||||
const notificationPath = `/instance?id=notifications`;
|
||||
const smtpPath = `/instance?id=smtpprovider`;
|
||||
const smsPath = `/instance?id=smsprovider`;
|
||||
@ -6,6 +13,11 @@ beforeEach(() => {
|
||||
cy.context().as('ctx');
|
||||
});
|
||||
|
||||
type SMTPProvider = {
|
||||
description: string;
|
||||
rowSelector: string;
|
||||
};
|
||||
|
||||
describe('instance notifications', () => {
|
||||
describe('notification settings', () => {
|
||||
it(`should show notification settings`, () => {
|
||||
@ -15,243 +27,195 @@ describe('instance notifications', () => {
|
||||
});
|
||||
|
||||
describe('smtp settings', () => {
|
||||
it(`should show SMTP provider settings`, () => {
|
||||
cy.visit(smtpPath);
|
||||
cy.contains('SMTP Provider');
|
||||
beforeEach(() => {
|
||||
const description = `mailgun-${uuidv4()}`;
|
||||
cy.wrap<SMTPProvider>({ description, rowSelector: `tr:contains('${description}')` }).as('provider');
|
||||
});
|
||||
|
||||
it(`should add Mailgun SMTP provider settings`, () => {
|
||||
let rowSelector = `a:contains('Mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587');
|
||||
cy.get('[formcontrolname="user"]').clear().type('user@example.com');
|
||||
cy.get('[formcontrolname="password"]').clear().type('password');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').clear().type('sender1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').clear().type('Test1');
|
||||
cy.get('[formcontrolname="replyToAddress"]').clear().type('replyto1@example.com');
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
cy.get('tr').contains('mailgun');
|
||||
cy.get('tr').contains('smtp.mailgun.org:587');
|
||||
cy.get('tr').contains('sender1@example.com');
|
||||
});
|
||||
it(`should change Mailgun SMTP provider settings`, () => {
|
||||
let rowSelector = `tr:contains('mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587');
|
||||
cy.get('[formcontrolname="user"]').should('have.value', 'user@example.com');
|
||||
cy.get('[formcontrolname="user"]').clear().type('change@example.com');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').should('have.value', 'sender1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').should('have.value', 'Test1');
|
||||
cy.get('[formcontrolname="replyToAddress"]').should('have.value', 'replyto1@example.com');
|
||||
cy.get('[formcontrolname="senderAddress"]').clear().type('senderchange1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').clear().type('Change1');
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).contains('mailgun');
|
||||
cy.get(rowSelector).contains('smtp.mailgun.org:587');
|
||||
cy.get(rowSelector).contains('senderchange1@example.com');
|
||||
});
|
||||
it(`should activate Mailgun SMTP provider settings`, () => {
|
||||
let rowSelector = `tr:contains('smtp.mailgun.org:587')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="activate-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
rowSelector = `tr:contains('smtp.mailgun.org:587')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]');
|
||||
cy.get(rowSelector).contains('mailgun');
|
||||
cy.get(rowSelector).contains('smtp.mailgun.org:587');
|
||||
cy.get(rowSelector).contains('senderchange1@example.com');
|
||||
});
|
||||
it(`should add Mailjet SMTP provider settings`, () => {
|
||||
let rowSelector = `a:contains('Mailjet')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'in-v3.mailjet.com:587');
|
||||
cy.get('[formcontrolname="user"]').clear().type('user@example.com');
|
||||
cy.get('[formcontrolname="password"]').clear().type('password');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').clear().type('sender2@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').clear().type('Test2');
|
||||
cy.get('[formcontrolname="replyToAddress"]').clear().type('replyto2@example.com');
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
rowSelector = `tr:contains('mailjet')`;
|
||||
cy.get(rowSelector).contains('mailjet');
|
||||
cy.get(rowSelector).contains('in-v3.mailjet.com:587');
|
||||
cy.get(rowSelector).contains('sender2@example.com');
|
||||
});
|
||||
it(`should activate Mailjet SMTP provider settings an disable Mailgun`, () => {
|
||||
let rowSelector = `tr:contains('in-v3.mailjet.com:587')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="activate-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]');
|
||||
cy.get(rowSelector).contains('mailjet');
|
||||
cy.get(rowSelector).contains('in-v3.mailjet.com:587');
|
||||
cy.get(rowSelector).contains('sender2@example.com');
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist');
|
||||
});
|
||||
it(`should deactivate Mailjet SMTP provider`, () => {
|
||||
let rowSelector = `tr:contains('mailjet')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="deactivate-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
rowSelector = `tr:contains('mailjet')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist');
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist');
|
||||
});
|
||||
it(`should delete Mailjet SMTP provider`, () => {
|
||||
let rowSelector = `tr:contains('mailjet')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type('Test2');
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
rowSelector = `tr:contains('mailjet')`;
|
||||
cy.get(rowSelector).should('not.exist');
|
||||
});
|
||||
it(`should delete Mailgun SMTP provider`, () => {
|
||||
let rowSelector = `tr:contains('mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type('Change1');
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).should('not.exist');
|
||||
cy.get<SMTPProvider>('@provider').then((provider) => {
|
||||
cy.visit(smtpPath);
|
||||
cy.get(`a:contains('Mailgun')`).click();
|
||||
cy.get('[formcontrolname="description"]').should('be.enabled').clear().type(provider.description);
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587');
|
||||
cy.get('[formcontrolname="user"]').should('be.enabled').clear().type('user@example.com');
|
||||
cy.get('[formcontrolname="password"]').should('be.enabled').clear().type('password');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').should('be.enabled').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').should('be.enabled').clear().type('sender1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').should('be.enabled').clear().type('Test1');
|
||||
cy.get('[formcontrolname="replyToAddress"]').should('be.enabled').clear().type('replyto1@example.com');
|
||||
cy.get('[data-e2e="continue-button"]').should('be.enabled').click();
|
||||
cy.get('[data-e2e="create-button"]').should('be.enabled').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').should('be.enabled').click();
|
||||
cy.get(provider.rowSelector).contains('smtp.mailgun.org:587');
|
||||
cy.get(provider.rowSelector).contains('sender1@example.com');
|
||||
});
|
||||
});
|
||||
|
||||
it(`should add Mailgun SMTP provider settings and activate it using wizard`, () => {
|
||||
let rowSelector = `a:contains('Mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587');
|
||||
cy.get('[formcontrolname="user"]').clear().type('user@example.com');
|
||||
cy.get('[formcontrolname="password"]').clear().type('password');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').clear().type('sender1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').clear().type('Test1');
|
||||
cy.get('[formcontrolname="replyToAddress"]').clear().type('replyto1@example.com');
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="activate-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
rowSelector = `tr:contains('smtp.mailgun.org:587')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]');
|
||||
cy.get(rowSelector).contains('mailgun');
|
||||
cy.get(rowSelector).contains('smtp.mailgun.org:587');
|
||||
cy.get(rowSelector).contains('sender1@example.com');
|
||||
cy.get<SMTPProvider>('@provider').then((provider) => {
|
||||
cy.visit(smtpPath);
|
||||
cy.get(`a:contains('Mailgun')`).click();
|
||||
cy.get('[formcontrolname="description"]').should('be.enabled').clear().type(provider.description);
|
||||
cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587');
|
||||
cy.get('[formcontrolname="user"]').should('be.enabled').clear().type('user@example.com');
|
||||
cy.get('[formcontrolname="password"]').should('be.enabled').clear().type('password');
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').should('be.enabled').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').should('be.enabled').clear().type('sender1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').should('be.enabled').clear().type('Test1');
|
||||
cy.get('[formcontrolname="replyToAddress"]').should('be.enabled').clear().type('replyto1@example.com');
|
||||
cy.get('[data-e2e="continue-button"]').should('be.enabled').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="activate-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
cy.get(provider.rowSelector).find('[data-e2e="active-provider"]');
|
||||
cy.get(provider.rowSelector).contains('smtp.mailgun.org:587');
|
||||
cy.get(provider.rowSelector).contains('sender1@example.com');
|
||||
});
|
||||
});
|
||||
it(`should add Mailgun SMTP provider settings and deactivate it using wizard`, () => {
|
||||
let rowSelector = `tr:contains('mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="deactivate-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist');
|
||||
|
||||
describe('with inactive existing', () => {
|
||||
beforeEach(() => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ description }) => {
|
||||
ensureSMTPProviderExists(ctx.api, description);
|
||||
});
|
||||
});
|
||||
cy.visit(smtpPath);
|
||||
});
|
||||
|
||||
it(`should change Mailgun SMTP provider settings`, () => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ rowSelector }) => {
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[formcontrolname="senderAddress"]').should('be.enabled').clear().type('senderchange1@example.com');
|
||||
cy.get('[formcontrolname="senderName"]').clear().type('Change1');
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
cy.get(rowSelector).contains('senderchange1@example.com');
|
||||
});
|
||||
});
|
||||
it(`should activate Mailgun SMTP provider settings`, () => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ rowSelector }) => {
|
||||
cy.get(rowSelector).find('[data-e2e="activate-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]');
|
||||
});
|
||||
});
|
||||
|
||||
it(`should delete Mailgun SMTP provider`, () => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ rowSelector }) => {
|
||||
cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().should('be.enabled').type('A Sender');
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get(rowSelector).should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should delete Mailgun SMTP provider`, () => {
|
||||
let rowSelector = `tr:contains('mailgun')`;
|
||||
cy.visit(smtpPath);
|
||||
cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type('Test1');
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
rowSelector = `tr:contains('mailgun')`;
|
||||
cy.get(rowSelector).should('not.exist');
|
||||
describe('with active existing', () => {
|
||||
beforeEach(() => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ description }) => {
|
||||
ensureSMTPProviderExists(ctx.api, description).then((providerId) => {
|
||||
activateSMTPProvider(ctx.api, providerId);
|
||||
});
|
||||
});
|
||||
});
|
||||
cy.pause();
|
||||
cy.visit(smtpPath);
|
||||
});
|
||||
|
||||
it(`should deactivate an existing Mailgun SMTP provider using wizard`, () => {
|
||||
cy.get<SMTPProvider>('@provider').then(({ rowSelector }) => {
|
||||
cy.get(rowSelector).click();
|
||||
cy.get('[data-e2e="continue-to-2nd-form"]').click();
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="deactivate-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="close-button"]').click();
|
||||
cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sms settings', () => {
|
||||
it(`should show SMS provider settings`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.contains('SMS Settings');
|
||||
beforeEach(() => {
|
||||
cy.wrap<string>(`twilio-${uuidv4()}`).as('uniqueSid');
|
||||
});
|
||||
|
||||
it(`should add SMS provider`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').clear().type('test');
|
||||
cy.get('[formcontrolname="token"]').clear().type('token');
|
||||
cy.get('[formcontrolname="senderNumber"]').clear().type('2312123132');
|
||||
cy.get('[data-e2e="save-sms-settings-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Inactive');
|
||||
describe('without existing', () => {
|
||||
beforeEach(() => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureSMSProviderDoesntExist(ctx.api);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should add SMS provider`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').should('be.enabled').clear().type('test');
|
||||
cy.get('[formcontrolname="token"]').should('be.enabled').clear().type('token');
|
||||
cy.get('[formcontrolname="senderNumber"]').should('be.enabled').clear().type('2312123132');
|
||||
cy.get('[data-e2e="save-sms-settings-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Inactive');
|
||||
});
|
||||
});
|
||||
|
||||
it(`should activate SMS provider`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Inactive');
|
||||
cy.get('[data-e2e="activate-sms-provider-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('.state').contains('Active');
|
||||
});
|
||||
describe('with inactive existing', () => {
|
||||
beforeEach(() => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureSMSProviderExists(ctx.api);
|
||||
cy.visit(smsPath);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should edit SMS provider`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Active');
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').should('have.value', 'test');
|
||||
cy.get('[formcontrolname="senderNumber"]').should('have.value', '2312123132');
|
||||
cy.get('[formcontrolname="sid"]').clear().type('test2');
|
||||
cy.get('[formcontrolname="senderNumber"]').clear().type('6666666666');
|
||||
cy.get('[data-e2e="save-sms-settings-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
});
|
||||
it(`should activate SMS provider`, () => {
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Inactive');
|
||||
cy.get('[data-e2e="activate-sms-provider-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('.state').contains('Active');
|
||||
});
|
||||
|
||||
it(`should contain edited values`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Active');
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').should('have.value', 'test2');
|
||||
cy.get('[formcontrolname="senderNumber"]').should('have.value', '6666666666');
|
||||
});
|
||||
it(`should edit SMS provider`, () => {
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').should('be.enabled').clear().type('test2');
|
||||
cy.get('[formcontrolname="senderNumber"]').should('be.enabled').clear().type('6666666666');
|
||||
cy.get('[data-e2e="save-sms-settings-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[formcontrolname="sid"]').should('have.value', 'test2');
|
||||
cy.get('[formcontrolname="senderNumber"]').should('have.value', '6666666666');
|
||||
});
|
||||
|
||||
it(`should edit SMS provider token`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Active');
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[data-e2e="edit-sms-token-button"]').click();
|
||||
cy.get('[data-e2e="notification-setting-password"]').clear().type('newsupertoken');
|
||||
cy.get('[data-e2e="save-notification-setting-password-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
});
|
||||
it(`should edit SMS provider token`, () => {
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('[data-e2e="new-twilio-button"]').click();
|
||||
cy.get('[data-e2e="edit-sms-token-button"]').click();
|
||||
cy.get('[data-e2e="notification-setting-password"]').should('be.enabled').clear().type('newsupertoken');
|
||||
cy.get('[data-e2e="save-notification-setting-password-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
});
|
||||
|
||||
it(`should remove SMS provider`, () => {
|
||||
cy.visit(smsPath);
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('.state').contains('Active');
|
||||
cy.get('[data-e2e="remove-sms-provider-button"]').click();
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
it(`should remove SMS provider`, () => {
|
||||
cy.get('h4').contains('Twilio');
|
||||
cy.get('[data-e2e="remove-sms-provider-button"]').click();
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -101,7 +101,7 @@ describe('instance secret generators', () => {
|
||||
it(`Initialization Mail should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="length1"]').clear().type('64');
|
||||
cy.get('input[id="length1"]').should('be.enabled').clear().type('64');
|
||||
cy.get('mat-slide-toggle#includeLowerLetters1 button').click();
|
||||
cy.get('button[id="saveSecretGenerator1"]').click();
|
||||
cy.wait(1000);
|
||||
@ -116,7 +116,7 @@ describe('instance secret generators', () => {
|
||||
it(`Email verification should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="length2"]').clear().type('64');
|
||||
cy.get('input[id="length2"]').should('be.enabled').clear().type('64');
|
||||
cy.get('mat-slide-toggle#includeUpperLetters2 button').click();
|
||||
cy.get('button[id="saveSecretGenerator2"]').click();
|
||||
cy.wait(1000);
|
||||
@ -131,7 +131,7 @@ describe('instance secret generators', () => {
|
||||
it(`Phone verification should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="expiry3"]').clear().type('10');
|
||||
cy.get('input[id="expiry3"]').should('be.enabled').clear().type('10');
|
||||
cy.get('mat-slide-toggle#includeSymbols3 button').click();
|
||||
cy.get('button[id="saveSecretGenerator3"]').click();
|
||||
cy.wait(1000);
|
||||
@ -146,7 +146,7 @@ describe('instance secret generators', () => {
|
||||
it(`Password Reset should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="expiry4"]').clear().type('5');
|
||||
cy.get('input[id="expiry4"]').should('be.enabled').clear().type('5');
|
||||
cy.get('mat-slide-toggle#includeDigits4 button').click();
|
||||
cy.get('button[id="saveSecretGenerator4"]').click();
|
||||
cy.wait(1000);
|
||||
@ -161,7 +161,7 @@ describe('instance secret generators', () => {
|
||||
it(`Passwordless Initialization should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="length5"]').clear().type('64');
|
||||
cy.get('input[id="length5"]').should('be.enabled').clear().type('64');
|
||||
cy.get('mat-slide-toggle#includeDigits5 button').click();
|
||||
cy.get('button[id="saveSecretGenerator5"]').click();
|
||||
cy.wait(1000);
|
||||
@ -176,8 +176,8 @@ describe('instance secret generators', () => {
|
||||
it(`App Secret should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="length6"]').clear().type('32');
|
||||
cy.get('input[id="expiry6"]').clear().type('120');
|
||||
cy.get('input[id="length6"]').should('be.enabled').clear().type('32');
|
||||
cy.get('input[id="expiry6"]').should('be.enabled').clear().type('120');
|
||||
cy.get('mat-slide-toggle#includeUpperLetters6 button').click();
|
||||
cy.get('button[id="saveSecretGenerator6"]').click();
|
||||
cy.wait(1000);
|
||||
@ -192,7 +192,7 @@ describe('instance secret generators', () => {
|
||||
it(`One Time Password (OTP) - SMS should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="expiry7"]').clear().type('120');
|
||||
cy.get('input[id="expiry7"]').should('be.enabled').clear().type('120');
|
||||
cy.get('mat-slide-toggle#includeLowerLetters7 button').click();
|
||||
cy.get('button[id="saveSecretGenerator7"]').click();
|
||||
cy.wait(1000);
|
||||
@ -207,8 +207,8 @@ describe('instance secret generators', () => {
|
||||
it(`One Time Password (OTP) should update settings`, () => {
|
||||
cy.visit(secretGeneratorSettingsPath);
|
||||
cy.wait(1000);
|
||||
cy.get('input[id="length8"]').clear().type('12');
|
||||
cy.get('input[id="expiry8"]').clear().type('90');
|
||||
cy.get('input[id="length8"]').should('be.enabled').clear().type('12');
|
||||
cy.get('input[id="expiry8"]').should('be.enabled').clear().type('90');
|
||||
cy.get('mat-slide-toggle#includeDigits8 button').click();
|
||||
cy.get('mat-slide-toggle#includeSymbols8 button').click();
|
||||
cy.get('button[id="saveSecretGenerator8"]').click();
|
||||
|
@ -29,9 +29,9 @@ describe('machines', () => {
|
||||
cy.get('[data-e2e="create-user-button"]').should('be.visible').click();
|
||||
cy.url().should('contain', 'users/create-machine');
|
||||
//force needed due to the prefilled username prefix
|
||||
cy.get('[formcontrolname="userName"]').type(machine.addName);
|
||||
cy.get('[formcontrolname="name"]').type('e2emachinename');
|
||||
cy.get('[formcontrolname="description"]').type('e2emachinedescription');
|
||||
cy.get('[formcontrolname="userName"]').should('be.enabled').type(machine.addName);
|
||||
cy.get('[formcontrolname="name"]').should('be.enabled').type('e2emachinename');
|
||||
cy.get('[formcontrolname="description"]').should('be.enabled').type('e2emachinedescription');
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
let loginName = machine.addName;
|
||||
@ -58,7 +58,7 @@ describe('machines', () => {
|
||||
it('should delete a machine', () => {
|
||||
const rowSelector = `tr:contains(${machine.removeName})`;
|
||||
cy.get(rowSelector).find('[data-e2e="enabled-delete-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type(loginName);
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().should('be.enabled').type(loginName);
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.shouldNotExist({
|
||||
|
@ -18,7 +18,7 @@ describe('organizations', () => {
|
||||
describe('add and delete org', () => {
|
||||
it('should create an org', () => {
|
||||
cy.visit(orgsPathCreate);
|
||||
cy.get('[data-e2e="org-name-input"]').focus().clear().type(newOrg);
|
||||
cy.get('[data-e2e="org-name-input"]').focus().clear().should('be.enabled').type(newOrg);
|
||||
cy.get('[data-e2e="create-org-button"]').click();
|
||||
cy.contains('tr', newOrg);
|
||||
});
|
||||
@ -30,7 +30,7 @@ describe('organizations', () => {
|
||||
cy.wait(1000);
|
||||
cy.get('[data-e2e="actions"]').click();
|
||||
cy.get('[data-e2e="delete"]', { timeout: 1000 }).should('be.visible').click();
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().clear().type(newOrg);
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().clear().should('be.enabled').type(newOrg);
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.contains('tr', newOrg).should('not.exist');
|
||||
@ -49,7 +49,7 @@ describe('organizations', () => {
|
||||
cy.get('[data-e2e="actions"]').click();
|
||||
cy.get('[data-e2e="rename"]', { timeout: 1000 }).should('be.visible').click();
|
||||
|
||||
cy.get('[data-e2e="name"]').focus().clear().type(testOrgNameChange);
|
||||
cy.get('[data-e2e="name"]').focus().clear().should('be.enabled').type(testOrgNameChange);
|
||||
cy.get('[data-e2e="dialog-submit"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.visit(orgPath);
|
||||
|
@ -45,7 +45,7 @@ describe('permissions', () => {
|
||||
|
||||
it('should add a manager', () => {
|
||||
cy.get('[data-e2e="add-member-button"]').click();
|
||||
cy.get('[data-e2e="add-member-input"]').type(testManagerUsername);
|
||||
cy.get('[data-e2e="add-member-input"]').should('be.enabled').type(testManagerUsername);
|
||||
cy.get('[data-e2e="user-option"]').first().click();
|
||||
cy.contains('[data-e2e="role-checkbox"]', roles[0]).click();
|
||||
cy.get('[data-e2e="confirm-add-member-button"]').click();
|
||||
@ -174,9 +174,9 @@ describe('permissions', () => {
|
||||
it('should add a role', () => {
|
||||
cy.get('[data-e2e="sidenav-element-roles"]').click();
|
||||
cy.get('[data-e2e="add-new-role"]').click();
|
||||
cy.get('[formcontrolname="key"]').type(testRoleName);
|
||||
cy.get('[formcontrolname="displayName"]').type('e2eroleundertestdisplay');
|
||||
cy.get('[formcontrolname="group"]').type('e2eroleundertestgroup');
|
||||
cy.get('[formcontrolname="key"]').should('be.enabled').type(testRoleName);
|
||||
cy.get('[formcontrolname="displayName"]').should('be.enabled').type('e2eroleundertestdisplay');
|
||||
cy.get('[formcontrolname="group"]').should('be.enabled').type('e2eroleundertestgroup');
|
||||
cy.get('[data-e2e="save-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.contains('tr', testRoleName);
|
||||
|
@ -1,29 +1,29 @@
|
||||
import { Context } from 'support/commands';
|
||||
import { ensureProjectDoesntExist, ensureProjectExists } from '../../support/api/projects';
|
||||
import { ensureProjectDoesntExist, ensureProjectExists, ensureRoleExists } from '../../support/api/projects';
|
||||
import { ensureOrgExists } from 'support/api/orgs';
|
||||
import { ensureProjectGrantDoesntExist, ensureProjectGrantExists } from '../../support/api/grants';
|
||||
|
||||
describe('projects', () => {
|
||||
beforeEach(() => {
|
||||
cy.context().as('ctx');
|
||||
});
|
||||
|
||||
const defaultOrg = 'e2eorgnewdefault';
|
||||
const foreignOrg = 'e2eorgnewdefault';
|
||||
const testProjectNameCreate = 'e2eprojectcreate';
|
||||
const testProjectNameDelete = 'e2eprojectdelete';
|
||||
const testProjectRole = 'e2eprojectrole';
|
||||
|
||||
describe('add project', () => {
|
||||
beforeEach(`ensure it doesn't exist already`, () => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureOrgExists(ctx, defaultOrg).then(() => {
|
||||
ensureProjectDoesntExist(ctx.api, testProjectNameCreate);
|
||||
cy.visit(`/projects`);
|
||||
});
|
||||
ensureProjectDoesntExist(ctx.api, testProjectNameCreate);
|
||||
cy.visit(`/projects`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a project', () => {
|
||||
cy.get('.add-project-button').click({ force: true });
|
||||
cy.get('input').type(testProjectNameCreate);
|
||||
cy.get('input').should('be.enabled').type(testProjectNameCreate);
|
||||
cy.get('[data-e2e="continue-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
});
|
||||
@ -32,41 +32,54 @@ describe('projects', () => {
|
||||
});
|
||||
|
||||
describe('create project grant', () => {
|
||||
const testRoleName = 'e2eroleundertestname';
|
||||
|
||||
beforeEach('ensure it exists', () => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
ensureProjectExists(ctx.api, testProjectNameCreate).as('projectId');
|
||||
cy.get<number>('@projectId').then((projectId) => {
|
||||
cy.visit(`/projects/${projectId}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should add a role', () => {
|
||||
const testRoleName = 'e2eroleundertestname';
|
||||
cy.get<number>('@projectId').then((projectId) => {
|
||||
cy.visit(`/projects/${projectId}`);
|
||||
});
|
||||
cy.get('[data-e2e="sidenav-element-roles"]').click();
|
||||
cy.get('[data-e2e="add-new-role"]').click();
|
||||
cy.get('[formcontrolname="key"]').should('be.enabled').type(testRoleName);
|
||||
cy.get('[formcontrolname="displayName"]').type('e2eroleundertestdisplay');
|
||||
cy.get('[formcontrolname="group"]').type('e2eroleundertestgroup');
|
||||
cy.get('[data-e2e="role-key-input"]').should('be.enabled').type(testRoleName);
|
||||
cy.get('[formcontrolname="displayName"]').should('be.enabled').type('e2eroleundertestdisplay');
|
||||
cy.get('[formcontrolname="group"]').should('be.enabled').type('e2eroleundertestgroup');
|
||||
cy.get('[data-e2e="save-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.contains('tr', testRoleName);
|
||||
});
|
||||
|
||||
it('should add a project grant', () => {
|
||||
const rowSelector = `tr:contains(${testRoleName})`;
|
||||
describe('with existing role, without project grant', () => {
|
||||
beforeEach(() => {
|
||||
cy.get<Context>('@ctx').then((ctx) => {
|
||||
cy.get<number>('@projectId').then((projectId) => {
|
||||
ensureOrgExists(ctx, foreignOrg).then((foreignOrgID) => {
|
||||
ensureRoleExists(ctx.api, projectId, testProjectRole);
|
||||
ensureProjectGrantDoesntExist(ctx, projectId, foreignOrgID);
|
||||
cy.visit(`/projects/${projectId}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
cy.get('[data-e2e="sidenav-element-projectgrants"]').click();
|
||||
cy.get('[data-e2e="create-project-grant-button"]').click();
|
||||
cy.get('[data-e2e="add-org-input"]').type(defaultOrg);
|
||||
cy.get('mat-option').contains(defaultOrg).click();
|
||||
cy.get('button').should('be.enabled');
|
||||
cy.get('[data-e2e="project-grant-continue"]').first().click();
|
||||
cy.get(rowSelector).find('input').click({ force: true });
|
||||
cy.get('[data-e2e="save-project-grant-button"]').click();
|
||||
cy.contains('tr', defaultOrg);
|
||||
cy.contains('tr', testRoleName);
|
||||
it('should add a project grant', () => {
|
||||
const rowSelector = `tr:contains(${testProjectRole})`;
|
||||
|
||||
cy.get('[data-e2e="sidenav-element-projectgrants"]').click();
|
||||
cy.get('[data-e2e="create-project-grant-button"]').click();
|
||||
cy.get('[data-e2e="add-org-input"]').should('be.enabled').type(foreignOrg);
|
||||
cy.get('mat-option').contains(foreignOrg).click();
|
||||
cy.get('button').should('be.enabled');
|
||||
cy.get('[data-e2e="project-grant-continue"]').first().click();
|
||||
cy.get(rowSelector).find('input').click({ force: true });
|
||||
cy.get('[data-e2e="save-project-grant-button"]').click();
|
||||
cy.contains('tr', foreignOrg);
|
||||
cy.contains('tr', testProjectRole);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -84,7 +97,7 @@ describe('projects', () => {
|
||||
cy.get('[data-e2e="toggle-grid"]').click();
|
||||
cy.get('[data-e2e="timestamp"]');
|
||||
cy.get(rowSelector).find('[data-e2e="delete-project-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDelete);
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().should('be.enabled').type(testProjectNameDelete);
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.shouldNotExist({
|
||||
@ -96,7 +109,7 @@ describe('projects', () => {
|
||||
it('removes the project from grid view', () => {
|
||||
const cardSelector = `[data-e2e="grid-card"]:contains(${testProjectNameDelete})`;
|
||||
cy.get(cardSelector).find('[data-e2e="delete-project-button"]').click({ force: true });
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().type(testProjectNameDelete);
|
||||
cy.get('[data-e2e="confirm-dialog-input"]').focus().should('be.enabled').type(testProjectNameDelete);
|
||||
cy.get('[data-e2e="confirm-dialog-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
cy.shouldNotExist({
|
||||
|
@ -17,7 +17,6 @@ describe('external link settings', () => {
|
||||
});
|
||||
|
||||
describe('instance', () => {
|
||||
|
||||
beforeEach(`visit`, () => {
|
||||
cy.visit(`/instance?id=privacypolicy`);
|
||||
});
|
||||
@ -94,5 +93,4 @@ describe('external link settings', () => {
|
||||
cy.get('[formcontrolname="docsLink"]').should('value', docsLink);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
|
@ -22,15 +22,25 @@ describe('oidc settings', () => {
|
||||
});
|
||||
|
||||
it(`should update oidc settings`, () => {
|
||||
cy.get('[formcontrolname="accessTokenLifetime"]').should('value', accessTokenPrecondition).clear().type('2');
|
||||
cy.get('[formcontrolname="idTokenLifetime"]').should('value', idTokenPrecondition).clear().type('24');
|
||||
cy.get('[formcontrolname="accessTokenLifetime"]')
|
||||
.should('value', accessTokenPrecondition)
|
||||
.clear()
|
||||
.should('be.enabled')
|
||||
.type('2');
|
||||
cy.get('[formcontrolname="idTokenLifetime"]')
|
||||
.should('value', idTokenPrecondition)
|
||||
.clear()
|
||||
.should('be.enabled')
|
||||
.type('24');
|
||||
cy.get('[formcontrolname="refreshTokenExpiration"]')
|
||||
.should('value', refreshTokenExpirationPrecondition)
|
||||
.clear()
|
||||
.should('be.enabled')
|
||||
.type('30');
|
||||
cy.get('[formcontrolname="refreshTokenIdleExpiration"]')
|
||||
.should('value', refreshTokenIdleExpirationPrecondition)
|
||||
.clear()
|
||||
.should('be.enabled')
|
||||
.type('7');
|
||||
cy.get('[data-e2e="save-button"]').click();
|
||||
cy.shouldConfirmSuccess();
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Context } from 'support/commands';
|
||||
import { ensureItemExists } from './ensure';
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { getOrgUnderTest } from './orgs';
|
||||
import { API, Entity } from './types';
|
||||
|
||||
export function ensureProjectGrantExists(ctx: Context, foreignOrgId: string, foreignProjectId: string) {
|
||||
return getOrgUnderTest(ctx).then((orgUnderTest) => {
|
||||
@ -16,3 +17,16 @@ export function ensureProjectGrantExists(ctx: Context, foreignOrgId: string, for
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function ensureProjectGrantDoesntExist(ctx: Context, projectId: number, foreignOrgId: string) {
|
||||
return getOrgUnderTest(ctx).then((orgUnderTest) => {
|
||||
console.log('removing grant to foreignOrgId', foreignOrgId, 'in orgUnderTest', orgUnderTest, 'projectId', projectId);
|
||||
return ensureItemDoesntExist(
|
||||
ctx.api,
|
||||
`${ctx.api.mgmtBaseURL}/projectgrants/_search`,
|
||||
(grant: any) => grant.grantedOrgId == foreignOrgId && grant.projectId == projectId,
|
||||
(grant: any) => `${ctx.api.mgmtBaseURL}/projects/${projectId}/grants/${grant.grantId}`,
|
||||
orgUnderTest.toString(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -23,7 +23,11 @@ export function ensureProjectDoesntExist(api: API, projectName: string, orgId?:
|
||||
}
|
||||
|
||||
class ResourceType {
|
||||
constructor(public resourcePath: string, public compareProperty: string, public identifierProperty: string) {}
|
||||
constructor(
|
||||
public resourcePath: string,
|
||||
public compareProperty: string,
|
||||
public identifierProperty: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
export const Apps = new ResourceType('apps', 'name', 'id');
|
||||
@ -47,19 +51,16 @@ export function ensureProjectResourceDoesntExist(
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureApplicationExists(api: API, projectId: number, appName: string) {
|
||||
export function ensureRoleExists(api: API, projectId: number, roleName: string) {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Apps.resourcePath}/_search`,
|
||||
(resource: any) => resource.name === appName,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Apps.resourcePath}/oidc`,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Roles.resourcePath}/_search`,
|
||||
(resource: any) => resource.key === roleName,
|
||||
`${api.mgmtBaseURL}/projects/${projectId}/${Roles.resourcePath}`,
|
||||
{
|
||||
name: appName,
|
||||
redirectUris: ['https://e2eredirecturl.org'],
|
||||
responseTypes: ['OIDC_RESPONSE_TYPE_CODE'],
|
||||
grantTypes: ['OIDC_GRANT_TYPE_AUTHORIZATION_CODE'],
|
||||
authMethodType: 'OIDC_AUTH_METHOD_TYPE_NONE',
|
||||
postLogoutRedirectUris: ['https://e2elogoutredirecturl.org'],
|
||||
name: roleName,
|
||||
roleKey: roleName,
|
||||
displayName: roleName,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
28
e2e/cypress/support/api/sms.ts
Normal file
28
e2e/cypress/support/api/sms.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { API, Entity } from './types';
|
||||
import { ensureSMTPProviderExists } from './smtp';
|
||||
|
||||
export function ensureSMSProviderExists(api: API) {
|
||||
// remove and create
|
||||
ensureSMSProviderDoesntExist(api);
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.adminBaseURL}/sms/_search`,
|
||||
({ twilio: { sid: foundSid } }: any) => foundSid === 'initial-sid',
|
||||
`${api.adminBaseURL}/sms/twilio`,
|
||||
{
|
||||
sid: 'initial-sid',
|
||||
senderNumber: 'initial-senderNumber',
|
||||
token: 'initial-token',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function ensureSMSProviderDoesntExist(api: API) {
|
||||
return ensureItemDoesntExist(
|
||||
api,
|
||||
`${api.adminBaseURL}/sms/_search`,
|
||||
(provider: any) => !!provider,
|
||||
(provider) => `${api.adminBaseURL}/sms/${provider.id}`,
|
||||
);
|
||||
}
|
32
e2e/cypress/support/api/smtp.ts
Normal file
32
e2e/cypress/support/api/smtp.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { ensureItemDoesntExist, ensureItemExists } from './ensure';
|
||||
import { API, Entity } from './types';
|
||||
|
||||
export function ensureSMTPProviderExists(api: API, providerDescription: string) {
|
||||
return ensureItemExists(
|
||||
api,
|
||||
`${api.adminBaseURL}/smtp/_search`,
|
||||
(provider: any) => {
|
||||
return provider.description === providerDescription;
|
||||
},
|
||||
`${api.adminBaseURL}/smtp`,
|
||||
{
|
||||
name: providerDescription,
|
||||
description: providerDescription,
|
||||
senderAddress: 'a@sender.com',
|
||||
senderName: 'A Sender',
|
||||
host: 'smtp.host.com:587',
|
||||
user: 'smtpuser',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function activateSMTPProvider(api: API, providerId: string) {
|
||||
return cy.request({
|
||||
method: 'POST',
|
||||
url: `${api.adminBaseURL}/smtp/${providerId}/_activate`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${api.token}`,
|
||||
},
|
||||
});
|
||||
}
|
@ -17,18 +17,18 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@types/pg": "^8.6.6",
|
||||
"cypress-wait-until": "^1.7.2",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"@types/pg": "^8.11.6",
|
||||
"cypress-wait-until": "^3.0.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mochawesome": "^7.1.3",
|
||||
"pg": "^8.8.0",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.8.4",
|
||||
"uuid": "^9.0.0",
|
||||
"pg": "^8.12.0",
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "^5.5.4",
|
||||
"uuid": "^10.0.0",
|
||||
"wait-on": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.8.3",
|
||||
"cypress": "^13.3.1"
|
||||
"@types/node": "^22.3.0",
|
||||
"cypress": "^13.13.3"
|
||||
}
|
||||
}
|
||||
|
500
e2e/yarn.lock
500
e2e/yarn.lock
@ -7,7 +7,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
|
||||
|
||||
"@cypress/request@^3.0.0":
|
||||
"@cypress/request@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960"
|
||||
integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==
|
||||
@ -68,20 +68,17 @@
|
||||
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
|
||||
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
|
||||
|
||||
"@types/node@*":
|
||||
version "20.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.0.tgz#c03de4572f114a940bc2ca909a33ddb2b925e470"
|
||||
integrity sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==
|
||||
"@types/node@*", "@types/node@^22.3.0":
|
||||
version "22.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.3.0.tgz#7f8da0e2b72c27c4f9bd3cb5ef805209d04d4f9e"
|
||||
integrity sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==
|
||||
dependencies:
|
||||
undici-types "~6.18.2"
|
||||
|
||||
"@types/node@^18.8.3":
|
||||
version "18.18.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.0.tgz#bd19d5133a6e5e2d0152ec079ac27c120e7f1763"
|
||||
integrity sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw==
|
||||
|
||||
"@types/pg@^8.6.6":
|
||||
version "8.10.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.10.3.tgz#39b3acba4f313a65c8fbb4b241fcb21cc1ba4126"
|
||||
integrity sha512-BACzsw64lCZesclRpZGu55tnqgFAYcrCBP92xLh1KLypZLCOsvJTSTgaoFVTy3lCys/aZTQzfeDxtjwrvdzL2g==
|
||||
"@types/pg@^8.11.6":
|
||||
version "8.11.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.11.6.tgz#a2d0fb0a14b53951a17df5197401569fb9c0c54b"
|
||||
integrity sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
pg-protocol "*"
|
||||
@ -93,14 +90,14 @@
|
||||
integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==
|
||||
|
||||
"@types/sizzle@^2.3.2":
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.4.tgz#cd6531924f60834fa4a1b8081f9eecf9bb1117f0"
|
||||
integrity sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag==
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.8.tgz#518609aefb797da19bf222feb199e8f653ff7627"
|
||||
integrity sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==
|
||||
|
||||
"@types/yauzl@^2.9.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.1.tgz#4e8f299f0934d60f36c74f59cb5a8483fd786691"
|
||||
integrity sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==
|
||||
version "2.10.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999"
|
||||
integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
@ -159,9 +156,9 @@ astral-regex@^2.0.0:
|
||||
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
|
||||
|
||||
async@^3.2.0:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
|
||||
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
|
||||
version "3.2.5"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
|
||||
integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
@ -179,24 +176,19 @@ aws-sign2@~0.7.0:
|
||||
integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
|
||||
integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.13.1.tgz#bb5f8b8a20739f6ae1caeaf7eea2c7913df8048e"
|
||||
integrity sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==
|
||||
|
||||
axios@^1.6.1:
|
||||
version "1.6.8"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66"
|
||||
integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==
|
||||
version "1.7.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2"
|
||||
integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.6"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
@ -219,14 +211,6 @@ bluebird@^3.7.2:
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
buffer-crc32@~0.2.3:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
@ -237,11 +221,6 @@ buffer-equal-constant-time@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
|
||||
|
||||
buffer-writer@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04"
|
||||
integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
|
||||
|
||||
buffer@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
|
||||
@ -255,13 +234,16 @@ cachedir@^2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d"
|
||||
integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==
|
||||
|
||||
call-bind@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
|
||||
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
|
||||
call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.2"
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
set-function-length "^1.2.1"
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
@ -282,9 +264,9 @@ check-more-types@^2.24.0:
|
||||
integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==
|
||||
|
||||
ci-info@^3.2.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
|
||||
integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
|
||||
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
@ -299,9 +281,9 @@ cli-cursor@^3.1.0:
|
||||
restore-cursor "^3.1.0"
|
||||
|
||||
cli-table3@~0.6.1:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2"
|
||||
integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==
|
||||
version "0.6.5"
|
||||
resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f"
|
||||
integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==
|
||||
dependencies:
|
||||
string-width "^4.2.0"
|
||||
optionalDependencies:
|
||||
@ -358,11 +340,6 @@ common-tags@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6"
|
||||
integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
@ -377,17 +354,17 @@ cross-spawn@^7.0.0:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
cypress-wait-until@^1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-1.7.2.tgz#7f534dd5a11c89b65359e7a0210f20d3dfc22107"
|
||||
integrity sha512-uZ+M8/MqRcpf+FII/UZrU7g1qYZ4aVlHcgyVopnladyoBrpoaMJ4PKZDrdOJ05H5RHbr7s9Tid635X3E+ZLU/Q==
|
||||
cypress-wait-until@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-3.0.2.tgz#c90dddfa4c46a2c422f5b91d486531c560bae46e"
|
||||
integrity sha512-iemies796dD5CgjG5kV0MnpEmKSH+s7O83ZoJLVzuVbZmm4lheMsZqAVT73hlMx4QlkwhxbyUzhOBUOZwoOe0w==
|
||||
|
||||
cypress@^13.3.1:
|
||||
version "13.7.2"
|
||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.7.2.tgz#61e841382abb20e0a9a063086ee0d850af3ef6bc"
|
||||
integrity sha512-FF5hFI5wlRIHY8urLZjJjj/YvfCBrRpglbZCLr/cYcL9MdDe0+5usa8kTIrDHthlEc9lwihbkb5dmwqBDNS2yw==
|
||||
cypress@^13.13.3:
|
||||
version "13.13.3"
|
||||
resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.13.3.tgz#21ee054bb4e00b3858f2e33b4f8f4e69128470a9"
|
||||
integrity sha512-hUxPrdbJXhUOTzuML+y9Av7CKoYznbD83pt8g3klgpioEha0emfx4WNIuVRx0C76r0xV2MIwAW9WYiXfVJYFQw==
|
||||
dependencies:
|
||||
"@cypress/request" "^3.0.0"
|
||||
"@cypress/request" "^3.0.1"
|
||||
"@cypress/xvfb" "^1.2.4"
|
||||
"@types/sinonjs__fake-timers" "8.1.1"
|
||||
"@types/sizzle" "^2.3.2"
|
||||
@ -426,7 +403,7 @@ cypress@^13.3.1:
|
||||
request-progress "^3.0.0"
|
||||
semver "^7.5.3"
|
||||
supports-color "^8.1.1"
|
||||
tmp "~0.2.1"
|
||||
tmp "~0.2.3"
|
||||
untildify "^4.0.0"
|
||||
yauzl "^2.10.0"
|
||||
|
||||
@ -443,9 +420,9 @@ dateformat@^4.5.1:
|
||||
integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==
|
||||
|
||||
dayjs@^1.10.4:
|
||||
version "1.11.10"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
|
||||
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
|
||||
version "1.11.12"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.12.tgz#5245226cc7f40a15bf52e0b99fd2a04669ccac1d"
|
||||
integrity sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.7"
|
||||
@ -455,21 +432,30 @@ debug@^3.1.0:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.1, debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||
version "4.3.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b"
|
||||
integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
define-data-property@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
|
||||
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.0.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
diff@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
|
||||
integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531"
|
||||
integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
@ -506,10 +492,22 @@ enquirer@^2.3.6:
|
||||
ansi-colors "^4.1.1"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
es-define-property@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
|
||||
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
|
||||
dependencies:
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
es-errors@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||
|
||||
escalade@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
|
||||
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
|
||||
|
||||
escape-html@^1.0.3:
|
||||
version "1.0.3"
|
||||
@ -635,35 +633,31 @@ fs-extra@^9.1.0:
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsu@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fsu/-/fsu-1.1.1.tgz#bd36d3579907c59d85b257a75b836aa9e0c31834"
|
||||
integrity sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
|
||||
get-intrinsic@^1.0.2:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
|
||||
integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
|
||||
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
|
||||
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
has "^1.0.3"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
has-proto "^1.0.1"
|
||||
has-symbols "^1.0.3"
|
||||
hasown "^2.0.0"
|
||||
|
||||
get-stream@^5.0.0, get-stream@^5.1.0:
|
||||
version "5.2.0"
|
||||
@ -686,18 +680,6 @@ getpass@^0.1.1:
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
global-dirs@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485"
|
||||
@ -705,6 +687,13 @@ global-dirs@^3.0.0:
|
||||
dependencies:
|
||||
ini "2.0.0"
|
||||
|
||||
gopd@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
||||
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
@ -715,22 +704,29 @@ has-flag@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
has-property-descriptors@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
|
||||
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
|
||||
has-proto@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
|
||||
integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
|
||||
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
|
||||
|
||||
has-symbols@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||
|
||||
has@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
hasown@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
function-bind "^1.1.2"
|
||||
|
||||
http-signature@~1.3.6:
|
||||
version "1.3.6"
|
||||
@ -756,19 +752,6 @@ indent-string@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ini@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
|
||||
@ -825,9 +808,9 @@ isstream@~0.1.2:
|
||||
integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
|
||||
|
||||
joi@^17.11.0:
|
||||
version "17.12.3"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.3.tgz#944646979cd3b460178547b12ba37aca8482f63d"
|
||||
integrity sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==
|
||||
version "17.13.3"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec"
|
||||
integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.3.0"
|
||||
"@hapi/topo" "^5.1.0"
|
||||
@ -864,10 +847,10 @@ jsonfile@^6.0.1:
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsonwebtoken@^8.5.1:
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
|
||||
integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
|
||||
jsonwebtoken@^9.0.2:
|
||||
version "9.0.2"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
|
||||
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
|
||||
dependencies:
|
||||
jws "^3.2.2"
|
||||
lodash.includes "^4.3.0"
|
||||
@ -878,7 +861,7 @@ jsonwebtoken@^8.5.1:
|
||||
lodash.isstring "^4.0.1"
|
||||
lodash.once "^4.0.0"
|
||||
ms "^2.1.1"
|
||||
semver "^5.6.0"
|
||||
semver "^7.5.4"
|
||||
|
||||
jsprim@^2.0.2:
|
||||
version "2.0.2"
|
||||
@ -1006,13 +989,6 @@ loose-envify@^1.4.0:
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
@ -1035,13 +1011,6 @@ mimic-fn@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
minimatch@^3.1.1:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.8:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
@ -1103,17 +1072,17 @@ object-assign@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||
|
||||
object-inspect@^1.9.0:
|
||||
version "1.12.3"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
|
||||
integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
|
||||
object-inspect@^1.13.1:
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
|
||||
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
|
||||
|
||||
obuf@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
|
||||
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
|
||||
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
@ -1144,16 +1113,6 @@ p-map@^4.0.0:
|
||||
dependencies:
|
||||
aggregate-error "^3.0.0"
|
||||
|
||||
packet-reader@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
|
||||
integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-key@^3.0.0, path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
@ -1174,10 +1133,10 @@ pg-cloudflare@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
|
||||
integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==
|
||||
|
||||
pg-connection-string@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475"
|
||||
integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==
|
||||
pg-connection-string@^2.6.4:
|
||||
version "2.6.4"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.4.tgz#f543862adfa49fa4e14bc8a8892d2a84d754246d"
|
||||
integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==
|
||||
|
||||
pg-int8@1.0.1:
|
||||
version "1.0.1"
|
||||
@ -1189,15 +1148,15 @@ pg-numeric@1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a"
|
||||
integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==
|
||||
|
||||
pg-pool@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7"
|
||||
integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==
|
||||
pg-pool@^3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2"
|
||||
integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==
|
||||
|
||||
pg-protocol@*, pg-protocol@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833"
|
||||
integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==
|
||||
pg-protocol@*, pg-protocol@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3"
|
||||
integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==
|
||||
|
||||
pg-types@^2.1.0:
|
||||
version "2.2.0"
|
||||
@ -1211,28 +1170,26 @@ pg-types@^2.1.0:
|
||||
postgres-interval "^1.1.0"
|
||||
|
||||
pg-types@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.1.tgz#31857e89d00a6c66b06a14e907c3deec03889542"
|
||||
integrity sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d"
|
||||
integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==
|
||||
dependencies:
|
||||
pg-int8 "1.0.1"
|
||||
pg-numeric "1.0.2"
|
||||
postgres-array "~3.0.1"
|
||||
postgres-bytea "~3.0.0"
|
||||
postgres-date "~2.0.1"
|
||||
postgres-date "~2.1.0"
|
||||
postgres-interval "^3.0.0"
|
||||
postgres-range "^1.1.1"
|
||||
|
||||
pg@^8.8.0:
|
||||
version "8.11.3"
|
||||
resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb"
|
||||
integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==
|
||||
pg@^8.12.0:
|
||||
version "8.12.0"
|
||||
resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79"
|
||||
integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==
|
||||
dependencies:
|
||||
buffer-writer "2.0.0"
|
||||
packet-reader "1.0.0"
|
||||
pg-connection-string "^2.6.2"
|
||||
pg-pool "^3.6.1"
|
||||
pg-protocol "^1.6.0"
|
||||
pg-connection-string "^2.6.4"
|
||||
pg-pool "^3.6.2"
|
||||
pg-protocol "^1.6.1"
|
||||
pg-types "^2.1.0"
|
||||
pgpass "1.x"
|
||||
optionalDependencies:
|
||||
@ -1277,10 +1234,10 @@ postgres-date@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
|
||||
integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
|
||||
|
||||
postgres-date@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.0.1.tgz#638b62e5c33764c292d37b08f5257ecb09231457"
|
||||
integrity sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==
|
||||
postgres-date@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0"
|
||||
integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==
|
||||
|
||||
postgres-interval@^1.1.0:
|
||||
version "1.2.0"
|
||||
@ -1295,14 +1252,14 @@ postgres-interval@^3.0.0:
|
||||
integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==
|
||||
|
||||
postgres-range@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.3.tgz#9ccd7b01ca2789eb3c2e0888b3184225fa859f76"
|
||||
integrity sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863"
|
||||
integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==
|
||||
|
||||
prettier@^2.7.1:
|
||||
version "2.8.8"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
||||
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
|
||||
prettier@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
|
||||
integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
|
||||
|
||||
pretty-bytes@^5.6.0:
|
||||
version "5.6.0"
|
||||
@ -1347,9 +1304,9 @@ pump@^3.0.0:
|
||||
once "^1.3.1"
|
||||
|
||||
punycode@^2.1.1:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
|
||||
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
|
||||
qs@6.10.4:
|
||||
version "6.10.4"
|
||||
@ -1394,16 +1351,9 @@ restore-cursor@^3.1.0:
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
rfdc@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
|
||||
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
|
||||
|
||||
rimraf@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca"
|
||||
integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
|
||||
|
||||
rxjs@^7.5.1, rxjs@^7.8.1:
|
||||
version "7.8.1"
|
||||
@ -1422,17 +1372,22 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^5.6.0:
|
||||
version "5.7.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
|
||||
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
|
||||
semver@^7.5.3, semver@^7.5.4:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
||||
semver@^7.5.3:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
set-function-length@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
define-data-property "^1.1.4"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
gopd "^1.0.1"
|
||||
has-property-descriptors "^1.0.2"
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
@ -1447,13 +1402,14 @@ shebang-regex@^3.0.0:
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
side-channel@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
|
||||
dependencies:
|
||||
call-bind "^1.0.0"
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
call-bind "^1.0.7"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
object-inspect "^1.13.1"
|
||||
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.7"
|
||||
@ -1484,9 +1440,9 @@ split2@^4.1.0:
|
||||
integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
|
||||
|
||||
sshpk@^1.14.1:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5"
|
||||
integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==
|
||||
version "1.18.0"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028"
|
||||
integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
@ -1546,26 +1502,24 @@ tcomb@^3.0.0, tcomb@^3.2.17:
|
||||
integrity sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==
|
||||
|
||||
throttleit@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"
|
||||
integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.1.tgz#304ec51631c3b770c65c6c6f76938b384000f4d5"
|
||||
integrity sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
|
||||
|
||||
tmp@~0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
|
||||
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
|
||||
dependencies:
|
||||
rimraf "^3.0.0"
|
||||
tmp@~0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae"
|
||||
integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==
|
||||
|
||||
tough-cookie@^4.1.3:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
|
||||
integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36"
|
||||
integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==
|
||||
dependencies:
|
||||
psl "^1.1.33"
|
||||
punycode "^2.1.1"
|
||||
@ -1573,9 +1527,9 @@ tough-cookie@^4.1.3:
|
||||
url-parse "^1.5.3"
|
||||
|
||||
tslib@^2.1.0:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
||||
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
@ -1594,10 +1548,15 @@ type-fest@^0.21.3:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
|
||||
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
|
||||
|
||||
typescript@^4.8.4:
|
||||
version "4.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
|
||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||
typescript@^5.5.4:
|
||||
version "5.5.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba"
|
||||
integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==
|
||||
|
||||
undici-types@~6.18.2:
|
||||
version "6.18.2"
|
||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.18.2.tgz#8b678cf939d4fc9ec56be3c68ed69c619dee28b0"
|
||||
integrity sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==
|
||||
|
||||
universalify@^0.2.0:
|
||||
version "0.2.0"
|
||||
@ -1605,9 +1564,9 @@ universalify@^0.2.0:
|
||||
integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
|
||||
integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
|
||||
|
||||
untildify@^4.0.0:
|
||||
version "4.0.0"
|
||||
@ -1622,20 +1581,20 @@ url-parse@^1.5.3:
|
||||
querystringify "^2.1.1"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
uuid@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294"
|
||||
integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==
|
||||
|
||||
uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uuid@^9.0.0:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||
|
||||
validator@^13.6.0:
|
||||
version "13.11.0"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b"
|
||||
integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
|
||||
version "13.12.0"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f"
|
||||
integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
@ -1697,11 +1656,6 @@ y18n@^5.0.5:
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
yargs-parser@^21.1.1:
|
||||
version "21.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
|
||||
|
8
go.mod
8
go.mod
@ -59,9 +59,9 @@ require (
|
||||
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
|
||||
github.com/ttacon/libphonenumber v1.2.1
|
||||
github.com/zitadel/logging v0.6.0
|
||||
github.com/zitadel/oidc/v3 v3.26.1
|
||||
github.com/zitadel/oidc/v3 v3.28.1
|
||||
github.com/zitadel/passwap v0.6.0
|
||||
github.com/zitadel/saml v0.1.3
|
||||
github.com/zitadel/saml v0.2.0
|
||||
github.com/zitadel/schema v1.3.0
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0
|
||||
@ -78,8 +78,8 @@ require (
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/oauth2 v0.22.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/text v0.16.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/text v0.17.0
|
||||
google.golang.org/api v0.187.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094
|
||||
google.golang.org/grpc v1.65.0
|
||||
|
16
go.sum
16
go.sum
@ -723,12 +723,12 @@ github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8=
|
||||
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank=
|
||||
github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow=
|
||||
github.com/zitadel/oidc/v3 v3.26.1 h1:/4wi2gxHByI9YYEjqcwEUx5GjsfDk8reudNP1Cp5Hgo=
|
||||
github.com/zitadel/oidc/v3 v3.26.1/go.mod h1:ZwBEqSviCpJVZiYashzo53bEGRGXi7amE5Q8PpQg9IM=
|
||||
github.com/zitadel/oidc/v3 v3.28.1 h1:PsbFm5CzEMQq9HBXUNJ8yvnWmtVYxpwV5Cinj7TTsHo=
|
||||
github.com/zitadel/oidc/v3 v3.28.1/go.mod h1:WmDFu3dZ9YNKrIoZkmxjGG8QyUR4PbbhsVVSY+rpojM=
|
||||
github.com/zitadel/passwap v0.6.0 h1:m9F3epFC0VkBXu25rihSLGyHvWiNlCzU5kk8RoI+SXQ=
|
||||
github.com/zitadel/passwap v0.6.0/go.mod h1:kqAiJ4I4eZvm3Y6oAk6hlEqlZZOkjMHraGXF90GG7LI=
|
||||
github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM=
|
||||
github.com/zitadel/saml v0.1.3/go.mod h1:MdkjyU3mwnTuh4lNnhPG+RyZL/VfzD72wUG/eWWBaXc=
|
||||
github.com/zitadel/saml v0.2.0 h1:vv7r+Xz43eAPCb+fImMaospD+TWRZQDkb78AbSJRcL4=
|
||||
github.com/zitadel/saml v0.2.0/go.mod h1:QqKcguOt7mMVI6tkEfpkyzwnYRdlmn3kYQj3VTPUw1g=
|
||||
github.com/zitadel/schema v1.3.0 h1:kQ9W9tvIwZICCKWcMvCEweXET1OcOyGEuFbHs4o5kg0=
|
||||
github.com/zitadel/schema v1.3.0/go.mod h1:NptN6mkBDFvERUCvZHlvWmmME+gmZ44xzwRXwhzsbtc=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
@ -871,8 +871,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -932,8 +932,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
|
@ -172,7 +172,6 @@ func SetLoginTextToDomain(req *admin_pb.SetCustomLoginTextsRequest) *domain.Cust
|
||||
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
|
||||
result.ExternalRegistrationUserOverview = text.ExternalRegistrationUserOverviewScreenTextPbToDomain(req.ExternalRegistrationUserOverviewText)
|
||||
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
|
||||
result.LinkingUserPrompt = text.LinkingUserPromptScreenTextPbToDomain(req.LinkingUserPromptText)
|
||||
result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText)
|
||||
result.ExternalNotFound = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText)
|
||||
result.LoginSuccess = text.SuccessLoginScreenTextPbToDomain(req.SuccessLoginText)
|
||||
|
@ -468,7 +468,7 @@ func (s *Server) getUserLinks(ctx context.Context, orgID string) (_ []*idp_pb.ID
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idpUserLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userLinksResourceOwner}}, false)
|
||||
idpUserLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: []query.SearchQuery{userLinksResourceOwner}}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1063,7 +1063,6 @@ func (s *Server) getCustomLoginTexts(ctx context.Context, org string, languages
|
||||
RegistrationUserText: text_grpc.RegistrationUserScreenTextToPb(text.RegistrationUser),
|
||||
ExternalRegistrationUserOverviewText: text_grpc.ExternalRegistrationUserOverviewScreenTextToPb(text.ExternalRegistrationUserOverview),
|
||||
RegistrationOrgText: text_grpc.RegistrationOrgScreenTextToPb(text.RegistrationOrg),
|
||||
LinkingUserPromptText: text_grpc.LinkingUserPromptScreenTextToPb(text.LinkingUserPrompt),
|
||||
LinkingUserDoneText: text_grpc.LinkingUserDoneScreenTextToPb(text.LinkingUsersDone),
|
||||
ExternalUserNotFoundText: text_grpc.ExternalUserNotFoundScreenTextToPb(text.ExternalNotFound),
|
||||
SuccessLoginText: text_grpc.SuccessLoginScreenTextToPb(text.LoginSuccess),
|
||||
|
@ -112,7 +112,7 @@ func (s *Server) RemoveIDP(ctx context.Context, req *admin_pb.RemoveIDPRequest)
|
||||
}
|
||||
userLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{
|
||||
Queries: []query.SearchQuery{idpQuery},
|
||||
}, true)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ func (s *Server) ListMyLinkedIDPs(ctx context.Context, req *auth_pb.ListMyLinked
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
links, err := s.query.IDPUserLinks(ctx, q, false)
|
||||
links, err := s.query.IDPUserLinks(ctx, q, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ func (s *Server) ListMyAuthFactors(ctx context.Context, _ *auth_pb.ListMyAuthFac
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false)
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func (s *Server) ListMyPasswordless(ctx context.Context, _ *auth_pb.ListMyPasswo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false)
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
|
||||
Actions: req.Actions,
|
||||
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
|
||||
WebKey: req.WebKey,
|
||||
DebugOIDCParentError: req.DebugOidcParentError,
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +58,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
|
||||
Actions: featureSourceToFlagPb(&f.Actions),
|
||||
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
|
||||
WebKey: featureSourceToFlagPb(&f.WebKey),
|
||||
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
DebugOidcParentError: &feature_pb.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
|
||||
},
|
||||
}
|
||||
got := instanceFeaturesToPb(arg)
|
||||
assert.Equal(t, want, got)
|
||||
|
@ -43,6 +43,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
|
||||
Actions: req.Actions,
|
||||
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
|
||||
WebKey: req.WebKey,
|
||||
DebugOIDCParentError: req.DebugOidcParentError,
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +58,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
|
||||
Actions: featureSourceToFlagPb(&f.Actions),
|
||||
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
|
||||
WebKey: featureSourceToFlagPb(&f.WebKey),
|
||||
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
DebugOidcParentError: &feature_pb.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
|
||||
},
|
||||
}
|
||||
got := instanceFeaturesToPb(arg)
|
||||
assert.Equal(t, want, got)
|
||||
|
@ -171,7 +171,6 @@ func SetLoginCustomTextToDomain(req *mgmt_pb.SetCustomLoginTextsRequest) *domain
|
||||
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
|
||||
result.ExternalRegistrationUserOverview = text.ExternalRegistrationUserOverviewScreenTextPbToDomain(req.ExternalRegistrationUserOverviewText)
|
||||
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
|
||||
result.LinkingUserPrompt = text.LinkingUserPromptScreenTextPbToDomain(req.LinkingUserPromptText)
|
||||
result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText)
|
||||
result.ExternalNotFound = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText)
|
||||
result.LoginSuccess = text.SuccessLoginScreenTextPbToDomain(req.SuccessLoginText)
|
||||
|
@ -91,7 +91,7 @@ func (s *Server) RemoveOrgIDP(ctx context.Context, req *mgmt_pb.RemoveOrgIDPRequ
|
||||
}
|
||||
userLinks, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{
|
||||
Queries: []query.SearchQuery{idpQuery},
|
||||
}, true)
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -608,7 +608,7 @@ func (s *Server) ListHumanAuthFactors(ctx context.Context, req *mgmt_pb.ListHuma
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false)
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -671,7 +671,7 @@ func (s *Server) ListHumanPasswordless(ctx context.Context, req *mgmt_pb.ListHum
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false)
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -892,7 +892,7 @@ func (s *Server) ListHumanLinkedIDPs(ctx context.Context, req *mgmt_pb.ListHuman
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.IDPUserLinks(ctx, queries, false)
|
||||
res, err := s.query.IDPUserLinks(ctx, queries, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
51
internal/api/grpc/resources/user/v3alpha/server.go
Normal file
51
internal/api/grpc/resources/user/v3alpha/server.go
Normal file
@ -0,0 +1,51 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
|
||||
)
|
||||
|
||||
var _ user.ZITADELUsersServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
user.UnimplementedZITADELUsersServer
|
||||
command *command.Commands
|
||||
userCodeAlg crypto.EncryptionAlgorithm
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
command *command.Commands,
|
||||
userCodeAlg crypto.EncryptionAlgorithm,
|
||||
) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
userCodeAlg: userCodeAlg,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
user.RegisterZITADELUsersServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return user.ZITADELUsers_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return user.ZITADELUsers_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return user.ZITADELUsers_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return user.RegisterZITADELUsersHandler
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
//go:build integration
|
||||
|
||||
package user_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
|
||||
)
|
||||
|
||||
var (
|
||||
IAMOwnerCTX, SystemCTX context.Context
|
||||
UserCTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client user.ZITADELUsersClient
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, _, cancel := integration.Contexts(time.Hour)
|
||||
defer cancel()
|
||||
|
||||
Tester = integration.NewTester(ctx)
|
||||
defer Tester.Done()
|
||||
|
||||
IAMOwnerCTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||||
SystemCTX = Tester.WithAuthorization(ctx, integration.SystemUser)
|
||||
UserCTX = Tester.WithAuthorization(ctx, integration.Login)
|
||||
Client = Tester.Client.UserV3Alpha
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
||||
|
||||
func ensureFeatureEnabled(t *testing.T, iamOwnerCTX context.Context) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
_, err = Tester.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
|
||||
UserSchema: gu.Ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
retryDuration := time.Minute
|
||||
if ctxDeadline, ok := iamOwnerCTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
require.EventuallyWithT(t,
|
||||
func(ttt *assert.CollectT) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(ttt, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
},
|
||||
retryDuration,
|
||||
100*time.Millisecond,
|
||||
"timed out waiting for ensuring instance feature")
|
||||
}
|
66
internal/api/grpc/resources/user/v3alpha/user.go
Normal file
66
internal/api/grpc/resources/user/v3alpha/user.go
Normal file
@ -0,0 +1,66 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
resource_object "github.com/zitadel/zitadel/internal/api/grpc/resources/object/v3alpha"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
|
||||
)
|
||||
|
||||
func (s *Server) CreateUser(ctx context.Context, req *user.CreateUserRequest) (_ *user.CreateUserResponse, err error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
schemauser, err := createUserRequestToCreateSchemaUser(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.command.CreateSchemaUser(ctx, schemauser, s.userCodeAlg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.CreateUserResponse{
|
||||
Details: resource_object.DomainToDetailsPb(schemauser.Details, object.OwnerType_OWNER_TYPE_ORG, schemauser.ResourceOwner),
|
||||
EmailCode: gu.Ptr(schemauser.ReturnCodeEmail),
|
||||
PhoneCode: gu.Ptr(schemauser.ReturnCodePhone),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createUserRequestToCreateSchemaUser(ctx context.Context, req *user.CreateUserRequest) (*command.CreateSchemaUser, error) {
|
||||
data, err := req.GetUser().GetData().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.CreateSchemaUser{
|
||||
ResourceOwner: authz.GetCtxData(ctx).OrgID,
|
||||
SchemaID: req.GetUser().GetSchemaId(),
|
||||
ID: req.GetUser().GetUserId(),
|
||||
Data: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUser(ctx context.Context, req *user.DeleteUserRequest) (_ *user.DeleteUserResponse, err error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.DeleteSchemaUser(ctx, req.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &user.DeleteUserResponse{
|
||||
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_ORG, details.ResourceOwner),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkUserSchemaEnabled(ctx context.Context) error {
|
||||
if authz.GetInstance(ctx).Features().UserSchema {
|
||||
return nil
|
||||
}
|
||||
return zerrors.ThrowPreconditionFailed(nil, "TODO", "Errors.UserSchema.NotEnabled")
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
//go:build integration
|
||||
|
||||
package user_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zitadel/logging"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||||
resource_object "github.com/zitadel/zitadel/pkg/grpc/resources/object/v3alpha"
|
||||
user "github.com/zitadel/zitadel/pkg/grpc/resources/user/v3alpha"
|
||||
)
|
||||
|
||||
func TestServer_CreateUser(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
schema := []byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}`)
|
||||
schemaResp := Tester.CreateUserSchema(IAMOwnerCTX, schema)
|
||||
permissionSchema := []byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"urn:zitadel:schema:permission": {
|
||||
"owner": "r",
|
||||
"self": "r"
|
||||
},
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}`)
|
||||
permissionSchemaResp := Tester.CreateUserSchema(IAMOwnerCTX, permissionSchema)
|
||||
orgResp := Tester.CreateOrganization(IAMOwnerCTX, gofakeit.Name(), gofakeit.Email())
|
||||
|
||||
type res struct {
|
||||
want *resource_object.Details
|
||||
returnCodeEmail bool
|
||||
returnCodePhone bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *user.CreateUserRequest
|
||||
res res
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "user create, no schemaID",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{Data: unmarshalJSON("{\"name\": \"user\"}")},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user create, no context",
|
||||
ctx: context.Background(),
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: schemaResp.GetDetails().GetId(),
|
||||
Data: unmarshalJSON("{\"name\": \"user\"}"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user create, no permission",
|
||||
ctx: UserCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: schemaResp.GetDetails().GetId(),
|
||||
Data: unmarshalJSON("{\"name\": \"user\"}"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user create, invalid schema permission, owner",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: permissionSchemaResp.GetDetails().GetId(),
|
||||
Data: unmarshalJSON("{\"name\": \"user\"}"),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user create, no user data",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: schemaResp.GetDetails().GetId(),
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_ORG,
|
||||
Id: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user create, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: schemaResp.GetDetails().GetId(),
|
||||
Data: unmarshalJSON("{\"name\": \"user\"}"),
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_ORG,
|
||||
Id: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "user create, full contact, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.CreateUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
User: &user.CreateUser{
|
||||
SchemaId: schemaResp.GetDetails().GetId(),
|
||||
Data: unmarshalJSON("{\"name\": \"user\"}"),
|
||||
Contact: &user.SetContact{
|
||||
Email: &user.SetEmail{
|
||||
Address: gofakeit.Email(),
|
||||
Verification: &user.SetEmail_ReturnCode{ReturnCode: &user.ReturnEmailVerificationCode{}},
|
||||
},
|
||||
Phone: &user.SetPhone{
|
||||
Number: gofakeit.Phone(),
|
||||
Verification: &user.SetPhone_ReturnCode{ReturnCode: &user.ReturnPhoneVerificationCode{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_ORG,
|
||||
Id: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
returnCodePhone: true,
|
||||
returnCodeEmail: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Tester.Client.UserV3Alpha.CreateUser(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.res.want, got.Details)
|
||||
if tt.res.returnCodeEmail {
|
||||
require.NotNil(t, got.EmailCode)
|
||||
}
|
||||
if tt.res.returnCodePhone {
|
||||
require.NotNil(t, got.PhoneCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteUser(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
schema := []byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}`)
|
||||
schemaResp := Tester.CreateUserSchema(IAMOwnerCTX, schema)
|
||||
orgResp := Tester.CreateOrganization(IAMOwnerCTX, gofakeit.Name(), gofakeit.Email())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
dep func(ctx context.Context, req *user.DeleteUserRequest) error
|
||||
req *user.DeleteUserRequest
|
||||
want *resource_object.Details
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "user delete, no userID",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.DeleteUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
UserId: "",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user delete, not existing",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &user.DeleteUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
UserId: "notexisting",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user delete, no context",
|
||||
ctx: context.Background(),
|
||||
dep: func(ctx context.Context, req *user.DeleteUserRequest) error {
|
||||
userResp := Tester.CreateSchemaUser(IAMOwnerCTX, orgResp.GetOrganizationId(), schemaResp.GetDetails().GetId(), []byte("{\"name\": \"user\"}"))
|
||||
req.UserId = userResp.GetDetails().GetId()
|
||||
return nil
|
||||
},
|
||||
req: &user.DeleteUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user delete, no permission",
|
||||
ctx: UserCTX,
|
||||
dep: func(ctx context.Context, req *user.DeleteUserRequest) error {
|
||||
userResp := Tester.CreateSchemaUser(IAMOwnerCTX, orgResp.GetOrganizationId(), schemaResp.GetDetails().GetId(), []byte("{\"name\": \"user\"}"))
|
||||
req.UserId = userResp.GetDetails().GetId()
|
||||
return nil
|
||||
},
|
||||
req: &user.DeleteUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "user delete, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
dep: func(ctx context.Context, req *user.DeleteUserRequest) error {
|
||||
userResp := Tester.CreateSchemaUser(ctx, orgResp.GetOrganizationId(), schemaResp.GetDetails().GetId(), []byte("{\"name\": \"user\"}"))
|
||||
req.UserId = userResp.GetDetails().GetId()
|
||||
return nil
|
||||
},
|
||||
req: &user.DeleteUserRequest{
|
||||
Organization: &object.Organization{
|
||||
Property: &object.Organization_OrgId{
|
||||
OrgId: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_ORG,
|
||||
Id: orgResp.GetOrganizationId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.dep != nil {
|
||||
err := tt.dep(tt.ctx, tt.req)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
got, err := Tester.Client.UserV3Alpha.DeleteUser(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.want, got.Details)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalJSON(data string) *structpb.Struct {
|
||||
user := new(structpb.Struct)
|
||||
err := user.UnmarshalJSON([]byte(data))
|
||||
if err != nil {
|
||||
logging.OnError(err).Fatal("unmarshalling user json")
|
||||
}
|
||||
return user
|
||||
}
|
255
internal/api/grpc/resources/userschema/v3alpha/query.go
Normal file
255
internal/api/grpc/resources/userschema/v3alpha/query.go
Normal file
@ -0,0 +1,255 @@
|
||||
package userschema
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
resource_object "github.com/zitadel/zitadel/internal/api/grpc/resources/object/v3alpha"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
func (s *Server) SearchUserSchemas(ctx context.Context, req *schema.SearchUserSchemasRequest) (*schema.SearchUserSchemasResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := s.searchUserSchemaToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUserSchema(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchemas, err := userSchemasToPb(res.UserSchemas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.SearchUserSchemasResponse{
|
||||
Details: resource_object.ToSearchDetailsPb(queries.SearchRequest, res.SearchResponse),
|
||||
Result: userSchemas,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetUserSchema(ctx context.Context, req *schema.GetUserSchemaRequest) (*schema.GetUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.GetUserSchemaByID(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := userSchemaToPb(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.GetUserSchemaResponse{
|
||||
UserSchema: userSchema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) searchUserSchemaToModel(req *schema.SearchUserSchemasRequest) (*query.UserSchemaSearchQueries, error) {
|
||||
offset, limit, asc, err := resource_object.SearchQueryPbToQuery(s.systemDefaults, req.Query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := userSchemaFiltersToQuery(req.Filters, 0) // start at level 0
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.UserSchemaSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: userSchemaFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userSchemaFieldNameToSortingColumn(field *schema.FieldName) query.Column {
|
||||
if field == nil {
|
||||
return query.UserSchemaCreationDateCol
|
||||
}
|
||||
switch *field {
|
||||
case schema.FieldName_FIELD_NAME_TYPE:
|
||||
return query.UserSchemaTypeCol
|
||||
case schema.FieldName_FIELD_NAME_STATE:
|
||||
return query.UserSchemaStateCol
|
||||
case schema.FieldName_FIELD_NAME_REVISION:
|
||||
return query.UserSchemaRevisionCol
|
||||
case schema.FieldName_FIELD_NAME_CHANGE_DATE:
|
||||
return query.UserSchemaChangeDateCol
|
||||
case schema.FieldName_FIELD_NAME_CREATION_DATE:
|
||||
return query.UserSchemaCreationDateCol
|
||||
case schema.FieldName_FIELD_NAME_UNSPECIFIED:
|
||||
return query.UserSchemaIDCol
|
||||
default:
|
||||
return query.UserSchemaIDCol
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemasToPb(schemas []*query.UserSchema) (_ []*schema.GetUserSchema, err error) {
|
||||
userSchemas := make([]*schema.GetUserSchema, len(schemas))
|
||||
for i, userSchema := range schemas {
|
||||
userSchemas[i], err = userSchemaToPb(userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return userSchemas, nil
|
||||
}
|
||||
|
||||
func userSchemaToPb(userSchema *query.UserSchema) (*schema.GetUserSchema, error) {
|
||||
s := new(structpb.Struct)
|
||||
if err := s.UnmarshalJSON(userSchema.Schema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.GetUserSchema{
|
||||
Details: resource_object.DomainToDetailsPb(&userSchema.ObjectDetails, object.OwnerType_OWNER_TYPE_INSTANCE, userSchema.ResourceOwner),
|
||||
Config: &schema.UserSchema{
|
||||
Type: userSchema.Type,
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: s,
|
||||
},
|
||||
PossibleAuthenticators: authenticatorTypesToPb(userSchema.PossibleAuthenticators),
|
||||
},
|
||||
State: userSchemaStateToPb(userSchema.State),
|
||||
Revision: userSchema.Revision,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorTypesToPb(authenticators []domain.AuthenticatorType) []schema.AuthenticatorType {
|
||||
authTypes := make([]schema.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
authTypes[i] = authenticatorTypeToPb(authenticator)
|
||||
}
|
||||
return authTypes
|
||||
}
|
||||
|
||||
func authenticatorTypeToPb(authenticator domain.AuthenticatorType) schema.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case domain.AuthenticatorTypeUsername:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME
|
||||
case domain.AuthenticatorTypePassword:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD
|
||||
case domain.AuthenticatorTypeWebAuthN:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN
|
||||
case domain.AuthenticatorTypeTOTP:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP
|
||||
case domain.AuthenticatorTypeOTPEmail:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL
|
||||
case domain.AuthenticatorTypeOTPSMS:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS
|
||||
case domain.AuthenticatorTypeAuthenticationKey:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY
|
||||
case domain.AuthenticatorTypeIdentityProvider:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER
|
||||
case domain.AuthenticatorTypeUnspecified:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
default:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToPb(state domain.UserSchemaState) schema.State {
|
||||
switch state {
|
||||
case domain.UserSchemaStateActive:
|
||||
return schema.State_STATE_ACTIVE
|
||||
case domain.UserSchemaStateInactive:
|
||||
return schema.State_STATE_INACTIVE
|
||||
case domain.UserSchemaStateUnspecified,
|
||||
domain.UserSchemaStateDeleted:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
default:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToDomain(state schema.State) domain.UserSchemaState {
|
||||
switch state {
|
||||
case schema.State_STATE_ACTIVE:
|
||||
return domain.UserSchemaStateActive
|
||||
case schema.State_STATE_INACTIVE:
|
||||
return domain.UserSchemaStateInactive
|
||||
case schema.State_STATE_UNSPECIFIED:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
default:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaFiltersToQuery(queries []*schema.SearchFilter, level uint8) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = userSchemaFilterToQuery(query, level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func userSchemaFilterToQuery(query *schema.SearchFilter, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-zsQ97", "Errors.Query.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Filter.(type) {
|
||||
case *schema.SearchFilter_StateFilter:
|
||||
return stateQueryToQuery(q.StateFilter)
|
||||
case *schema.SearchFilter_TypeFilter:
|
||||
return typeQueryToQuery(q.TypeFilter)
|
||||
case *schema.SearchFilter_IdFilter:
|
||||
return idQueryToQuery(q.IdFilter)
|
||||
case *schema.SearchFilter_OrFilter:
|
||||
return orQueryToQuery(q.OrFilter, level)
|
||||
case *schema.SearchFilter_AndFilter:
|
||||
return andQueryToQuery(q.AndFilter, level)
|
||||
case *schema.SearchFilter_NotFilter:
|
||||
return notQueryToQuery(q.NotFilter, level)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func stateQueryToQuery(q *schema.StateFilter) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaStateSearchQuery(userSchemaStateToDomain(q.GetState()))
|
||||
}
|
||||
|
||||
func typeQueryToQuery(q *schema.TypeFilter) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaTypeSearchQuery(q.GetType(), resource_object.TextMethodPbToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func idQueryToQuery(q *schema.IDFilter) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaIDSearchQuery(q.GetId(), resource_object.TextMethodPbToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func orQueryToQuery(q *schema.OrFilter, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaFiltersToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserOrSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func andQueryToQuery(q *schema.AndFilter, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaFiltersToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserAndSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func notQueryToQuery(q *schema.NotFilter, level uint8) (query.SearchQuery, error) {
|
||||
mappedQuery, err := userSchemaFilterToQuery(q.GetFilter(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserNotSearchQuery(mappedQuery)
|
||||
}
|
@ -0,0 +1,317 @@
|
||||
//go:build integration
|
||||
|
||||
package userschema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/resources/object/v3alpha"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
func TestServer_ListUserSchemas(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
userSchema := new(structpb.Struct)
|
||||
err := userSchema.UnmarshalJSON([]byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`))
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.SearchUserSchemasRequest
|
||||
prepare func(request *schema.SearchUserSchemasRequest, resp *schema.SearchUserSchemasResponse) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.SearchUserSchemasResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.SearchUserSchemasRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not found, error",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.SearchUserSchemasRequest{
|
||||
Filters: []*schema.SearchFilter{
|
||||
{
|
||||
Filter: &schema.SearchFilter_IdFilter{
|
||||
IdFilter: &schema.IDFilter{
|
||||
Id: "notexisting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.SearchUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
AppliedLimit: 100,
|
||||
},
|
||||
Result: []*schema.GetUserSchema{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single (id), ok",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.SearchUserSchemasRequest{},
|
||||
prepare: func(request *schema.SearchUserSchemasRequest, resp *schema.SearchUserSchemasResponse) error {
|
||||
schemaType := gofakeit.Name()
|
||||
createResp := Tester.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
|
||||
request.Filters = []*schema.SearchFilter{
|
||||
{
|
||||
Filter: &schema.SearchFilter_IdFilter{
|
||||
IdFilter: &schema.IDFilter{
|
||||
Id: createResp.GetDetails().GetId(),
|
||||
Method: object.TextFilterMethod_TEXT_FILTER_METHOD_EQUALS,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
resp.Result[0].Config.Type = schemaType
|
||||
resp.Result[0].Details = createResp.GetDetails()
|
||||
// as schema is freshly created, the changed date is the created date
|
||||
resp.Result[0].Details.Created = resp.Result[0].Details.GetChanged()
|
||||
resp.Details.Timestamp = resp.Result[0].Details.GetChanged()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.SearchUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
AppliedLimit: 100,
|
||||
},
|
||||
Result: []*schema.GetUserSchema{
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Config: &schema.UserSchema{
|
||||
Type: "",
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: userSchema,
|
||||
},
|
||||
PossibleAuthenticators: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple (type), ok",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.SearchUserSchemasRequest{},
|
||||
prepare: func(request *schema.SearchUserSchemasRequest, resp *schema.SearchUserSchemasResponse) error {
|
||||
schemaType := gofakeit.Name()
|
||||
schemaType1 := schemaType + "_1"
|
||||
schemaType2 := schemaType + "_2"
|
||||
createResp := Tester.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType1)
|
||||
createResp2 := Tester.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType2)
|
||||
|
||||
request.SortingColumn = gu.Ptr(schema.FieldName_FIELD_NAME_TYPE)
|
||||
request.Query = &object.SearchQuery{Desc: false}
|
||||
request.Filters = []*schema.SearchFilter{
|
||||
{
|
||||
Filter: &schema.SearchFilter_TypeFilter{
|
||||
TypeFilter: &schema.TypeFilter{
|
||||
Type: schemaType,
|
||||
Method: object.TextFilterMethod_TEXT_FILTER_METHOD_STARTS_WITH,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp.Result[0].Config.Type = schemaType1
|
||||
resp.Result[0].Details = createResp.GetDetails()
|
||||
resp.Result[1].Config.Type = schemaType2
|
||||
resp.Result[1].Details = createResp2.GetDetails()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.SearchUserSchemasResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 2,
|
||||
AppliedLimit: 100,
|
||||
},
|
||||
Result: []*schema.GetUserSchema{
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Config: &schema.UserSchema{
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: userSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Config: &schema.UserSchema{
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: userSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.prepare != nil {
|
||||
err := tt.args.prepare(tt.args.req, tt.want)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
retryDuration := 20 * time.Second
|
||||
if ctxDeadline, ok := IAMOwnerCTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, err := Client.SearchUserSchemas(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(ttt, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(ttt, err)
|
||||
|
||||
// always first check length, otherwise its failed anyway
|
||||
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||
for i := range tt.want.Result {
|
||||
want := tt.want.Result[i]
|
||||
got := got.Result[i]
|
||||
|
||||
integration.AssertResourceDetails(t, want.GetDetails(), got.GetDetails())
|
||||
want.Details = got.Details
|
||||
grpc.AllFieldsEqual(t, want.ProtoReflect(), got.ProtoReflect(), grpc.CustomMappers)
|
||||
}
|
||||
integration.AssertListDetails(t, tt.want, got)
|
||||
}, retryDuration, time.Millisecond*100, "timeout waiting for expected user schema result")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_GetUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
userSchema := new(structpb.Struct)
|
||||
err := userSchema.UnmarshalJSON([]byte(`{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}`))
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.GetUserSchemaRequest
|
||||
prepare func(request *schema.GetUserSchemaRequest, resp *schema.GetUserSchemaResponse) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.GetUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission",
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.GetUserSchemaRequest{},
|
||||
prepare: func(request *schema.GetUserSchemaRequest, resp *schema.GetUserSchemaResponse) error {
|
||||
schemaType := gofakeit.Name()
|
||||
createResp := Tester.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
|
||||
request.Id = createResp.GetDetails().GetId()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.GetUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "get, ok",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.GetUserSchemaRequest{},
|
||||
prepare: func(request *schema.GetUserSchemaRequest, resp *schema.GetUserSchemaResponse) error {
|
||||
schemaType := gofakeit.Name()
|
||||
createResp := Tester.CreateUserSchemaEmptyWithType(IAMOwnerCTX, schemaType)
|
||||
request.Id = createResp.GetDetails().GetId()
|
||||
|
||||
resp.UserSchema.Config.Type = schemaType
|
||||
resp.UserSchema.Details = createResp.GetDetails()
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.GetUserSchemaResponse{
|
||||
UserSchema: &schema.GetUserSchema{
|
||||
State: schema.State_STATE_ACTIVE,
|
||||
Revision: 1,
|
||||
Config: &schema.UserSchema{
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: userSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.prepare != nil {
|
||||
err := tt.args.prepare(tt.args.req, tt.want)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
retryDuration := 5 * time.Second
|
||||
if ctxDeadline, ok := IAMOwnerCTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, err := Client.GetUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err, "Error: "+err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
wantSchema := tt.want.GetUserSchema()
|
||||
gotSchema := got.GetUserSchema()
|
||||
integration.AssertResourceDetails(t, wantSchema.GetDetails(), gotSchema.GetDetails())
|
||||
tt.want.UserSchema.Details = got.GetUserSchema().GetDetails()
|
||||
grpc.AllFieldsEqual(t, tt.want.ProtoReflect(), got.ProtoReflect(), grpc.CustomMappers)
|
||||
}
|
||||
}, retryDuration, time.Millisecond*100, "timeout waiting for expected user schema result")
|
||||
})
|
||||
}
|
||||
}
|
65
internal/api/grpc/resources/userschema/v3alpha/server.go
Normal file
65
internal/api/grpc/resources/userschema/v3alpha/server.go
Normal file
@ -0,0 +1,65 @@
|
||||
package userschema
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
var _ schema.ZITADELUserSchemasServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
schema.UnimplementedZITADELUserSchemasServer
|
||||
systemDefaults systemdefaults.SystemDefaults
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
systemDefaults systemdefaults.SystemDefaults,
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
) *Server {
|
||||
return &Server{
|
||||
systemDefaults: systemDefaults,
|
||||
command: command,
|
||||
query: query,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
schema.RegisterZITADELUserSchemasServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return schema.ZITADELUserSchemas_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return schema.ZITADELUserSchemas_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return schema.ZITADELUserSchemas_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return schema.RegisterZITADELUserSchemasHandler
|
||||
}
|
||||
|
||||
func checkUserSchemaEnabled(ctx context.Context) error {
|
||||
if authz.GetInstance(ctx).Features().UserSchema {
|
||||
return nil
|
||||
}
|
||||
return zerrors.ThrowPreconditionFailed(nil, "SCHEMA-SFjk3", "Errors.UserSchema.NotEnabled")
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
//go:build integration
|
||||
|
||||
package userschema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
var (
|
||||
IAMOwnerCTX, SystemCTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client schema.ZITADELUserSchemasClient
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, _, cancel := integration.Contexts(5 * time.Minute)
|
||||
defer cancel()
|
||||
|
||||
Tester = integration.NewTester(ctx)
|
||||
defer Tester.Done()
|
||||
|
||||
IAMOwnerCTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||||
SystemCTX = Tester.WithAuthorization(ctx, integration.SystemUser)
|
||||
Client = Tester.Client.UserSchemaV3
|
||||
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
||||
|
||||
func ensureFeatureEnabled(t *testing.T, iamOwnerCTX context.Context) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
_, err = Tester.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
|
||||
UserSchema: gu.Ptr(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
retryDuration := time.Minute
|
||||
if ctxDeadline, ok := iamOwnerCTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
require.EventuallyWithT(t,
|
||||
func(ttt *assert.CollectT) {
|
||||
f, err := Tester.Client.FeatureV2.GetInstanceFeatures(iamOwnerCTX, &feature.GetInstanceFeaturesRequest{
|
||||
Inheritance: true,
|
||||
})
|
||||
require.NoError(ttt, err)
|
||||
if f.UserSchema.GetEnabled() {
|
||||
return
|
||||
}
|
||||
},
|
||||
retryDuration,
|
||||
100*time.Millisecond,
|
||||
"timed out waiting for ensuring instance feature")
|
||||
}
|
159
internal/api/grpc/resources/userschema/v3alpha/userschema.go
Normal file
159
internal/api/grpc/resources/userschema/v3alpha/userschema.go
Normal file
@ -0,0 +1,159 @@
|
||||
package userschema
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
resource_object "github.com/zitadel/zitadel/internal/api/grpc/resources/object/v3alpha"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
func (s *Server) CreateUserSchema(ctx context.Context, req *schema.CreateUserSchemaRequest) (*schema.CreateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
userSchema, err := createUserSchemaToCommand(req, instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.command.CreateUserSchema(ctx, userSchema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.CreateUserSchemaResponse{
|
||||
Details: resource_object.DomainToDetailsPb(userSchema.Details, object.OwnerType_OWNER_TYPE_INSTANCE, instanceID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) PatchUserSchema(ctx context.Context, req *schema.PatchUserSchemaRequest) (*schema.PatchUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
userSchema, err := patchUserSchemaToCommand(req, instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := s.command.ChangeUserSchema(ctx, userSchema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.PatchUserSchemaResponse{
|
||||
Details: resource_object.DomainToDetailsPb(userSchema.Details, object.OwnerType_OWNER_TYPE_INSTANCE, instanceID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUserSchema(ctx context.Context, req *schema.DeactivateUserSchemaRequest) (*schema.DeactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
details, err := s.command.DeactivateUserSchema(ctx, req.GetId(), instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeactivateUserSchemaResponse{
|
||||
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_INSTANCE, instanceID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUserSchema(ctx context.Context, req *schema.ReactivateUserSchemaRequest) (*schema.ReactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
details, err := s.command.ReactivateUserSchema(ctx, req.GetId(), instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.ReactivateUserSchemaResponse{
|
||||
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_INSTANCE, instanceID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUserSchema(ctx context.Context, req *schema.DeleteUserSchemaRequest) (*schema.DeleteUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
details, err := s.command.DeleteUserSchema(ctx, req.GetId(), instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeleteUserSchemaResponse{
|
||||
Details: resource_object.DomainToDetailsPb(details, object.OwnerType_OWNER_TYPE_INSTANCE, instanceID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createUserSchemaToCommand(req *schema.CreateUserSchemaRequest, resourceOwner string) (*command.CreateUserSchema, error) {
|
||||
schema, err := req.GetUserSchema().GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.CreateUserSchema{
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: req.GetUserSchema().GetType(),
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetUserSchema().GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func patchUserSchemaToCommand(req *schema.PatchUserSchemaRequest, resourceOwner string) (*command.ChangeUserSchema, error) {
|
||||
schema, err := req.GetUserSchema().GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ty *string
|
||||
if req.GetUserSchema() != nil && req.GetUserSchema().GetType() != "" {
|
||||
ty = gu.Ptr(req.GetUserSchema().GetType())
|
||||
}
|
||||
return &command.ChangeUserSchema{
|
||||
ID: req.GetId(),
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: ty,
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetUserSchema().GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorsToDomain(authenticators []schema.AuthenticatorType) []domain.AuthenticatorType {
|
||||
if authenticators == nil {
|
||||
return nil
|
||||
}
|
||||
types := make([]domain.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
types[i] = authenticatorTypeToDomain(authenticator)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func authenticatorTypeToDomain(authenticator schema.AuthenticatorType) domain.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME:
|
||||
return domain.AuthenticatorTypeUsername
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD:
|
||||
return domain.AuthenticatorTypePassword
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN:
|
||||
return domain.AuthenticatorTypeWebAuthN
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP:
|
||||
return domain.AuthenticatorTypeTOTP
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL:
|
||||
return domain.AuthenticatorTypeOTPEmail
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS:
|
||||
return domain.AuthenticatorTypeOTPSMS
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY:
|
||||
return domain.AuthenticatorTypeAuthenticationKey
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER:
|
||||
return domain.AuthenticatorTypeIdentityProvider
|
||||
default:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
}
|
||||
}
|
@ -0,0 +1,827 @@
|
||||
//go:build integration
|
||||
|
||||
package userschema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||||
resource_object "github.com/zitadel/zitadel/pkg/grpc/resources/object/v3alpha"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/resources/userschema/v3alpha"
|
||||
)
|
||||
|
||||
func TestServer_CreateUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
ctx context.Context
|
||||
req *schema.CreateUserSchemaRequest
|
||||
want *schema.CreateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission, error",
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty type",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: "",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty schema, error",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid schema, error",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "no authenticators, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid authenticator, error",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with authenticator, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with invalid permission, error",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"urn:zitadel:schema:permission": "read"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with valid permission, ok",
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.CreateUserSchemaRequest{
|
||||
UserSchema: &schema.UserSchema{
|
||||
Type: gofakeit.Name(),
|
||||
DataType: &schema.UserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"urn:zitadel:schema:permission": {
|
||||
"owner": "rw",
|
||||
"self": "r"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.CreateUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.CreateUserSchema(tt.ctx, tt.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
integration.AssertResourceDetails(t, tt.want.GetDetails(), got.GetDetails())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_UpdateUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.PatchUserSchemaRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare func(request *schema.PatchUserSchemaRequest) error
|
||||
args args
|
||||
want *schema.PatchUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "missing permission, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
Type: gu.Ptr(gofakeit.Name()),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "missing id, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "not existing, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
request.Id = "notexisting"
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty type, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
Type: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update type, ok",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
Type: gu.Ptr(gofakeit.Name()),
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.PatchUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty schema, ok",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
DataType: &schema.PatchUserSchema_Schema{},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.PatchUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid schema, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
DataType: &schema.PatchUserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update schema, ok",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
DataType: &schema.PatchUserSchema_Schema{
|
||||
Schema: func() *structpb.Struct {
|
||||
s := new(structpb.Struct)
|
||||
err := s.UnmarshalJSON([]byte(`
|
||||
{
|
||||
"$schema": "urn:zitadel:schema:v1",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
`))
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.PatchUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid authenticator, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "update authenticator, ok",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
PossibleAuthenticators: []schema.AuthenticatorType{
|
||||
schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: &schema.PatchUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inactive, error",
|
||||
prepare: func(request *schema.PatchUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.PatchUserSchemaRequest{
|
||||
UserSchema: &schema.PatchUserSchema{
|
||||
Type: gu.Ptr(gofakeit.Name()),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.PatchUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.want.GetDetails(), got.GetDetails())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeactivateUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.DeactivateUserSchemaRequest
|
||||
prepare func(request *schema.DeactivateUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.DeactivateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
IAMOwnerCTX,
|
||||
&schema.DeactivateUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "active, ok",
|
||||
args: args{
|
||||
IAMOwnerCTX,
|
||||
&schema.DeactivateUserSchemaRequest{},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.DeactivateUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inactive, error",
|
||||
args: args{
|
||||
IAMOwnerCTX,
|
||||
&schema.DeactivateUserSchemaRequest{},
|
||||
func(request *schema.DeactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeactivateUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.want.GetDetails(), got.GetDetails())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_ReactivateUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.ReactivateUserSchemaRequest
|
||||
prepare func(request *schema.ReactivateUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.ReactivateUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
IAMOwnerCTX,
|
||||
&schema.ReactivateUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.ReactivateUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "active, error",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.ReactivateUserSchemaRequest{},
|
||||
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "inactive, ok",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.ReactivateUserSchemaRequest{},
|
||||
prepare: func(request *schema.ReactivateUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeactivateUserSchema(IAMOwnerCTX, &schema.DeactivateUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
want: &schema.ReactivateUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.ReactivateUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.want.GetDetails(), got.GetDetails())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_DeleteUserSchema(t *testing.T) {
|
||||
ensureFeatureEnabled(t, IAMOwnerCTX)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *schema.DeleteUserSchemaRequest
|
||||
prepare func(request *schema.DeleteUserSchemaRequest) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *schema.DeleteUserSchemaResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "not existing, error",
|
||||
args: args{
|
||||
IAMOwnerCTX,
|
||||
&schema.DeleteUserSchemaRequest{
|
||||
Id: "notexisting",
|
||||
},
|
||||
func(request *schema.DeleteUserSchemaRequest) error { return nil },
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "delete, ok",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.DeleteUserSchemaRequest{},
|
||||
prepare: func(request *schema.DeleteUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: &schema.DeleteUserSchemaResponse{
|
||||
Details: &resource_object.Details{
|
||||
Changed: timestamppb.Now(),
|
||||
Owner: &object.Owner{
|
||||
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||||
Id: Tester.Instance.InstanceID(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deleted, error",
|
||||
args: args{
|
||||
ctx: IAMOwnerCTX,
|
||||
req: &schema.DeleteUserSchemaRequest{},
|
||||
prepare: func(request *schema.DeleteUserSchemaRequest) error {
|
||||
schemaID := Tester.CreateUserSchemaEmpty(IAMOwnerCTX).GetDetails().GetId()
|
||||
request.Id = schemaID
|
||||
_, err := Client.DeleteUserSchema(IAMOwnerCTX, &schema.DeleteUserSchemaRequest{
|
||||
Id: schemaID,
|
||||
})
|
||||
return err
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.prepare(tt.args.req)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := Client.DeleteUserSchema(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
integration.AssertResourceDetails(t, tt.want.GetDetails(), got.GetDetails())
|
||||
})
|
||||
}
|
||||
}
|
@ -64,7 +64,6 @@ func CustomLoginTextToPb(text *domain.CustomLoginText) *text_pb.LoginCustomText
|
||||
RegistrationUserText: RegistrationUserScreenTextToPb(text.RegistrationUser),
|
||||
ExternalRegistrationUserOverviewText: ExternalRegistrationUserOverviewScreenTextToPb(text.ExternalRegistrationUserOverview),
|
||||
RegistrationOrgText: RegistrationOrgScreenTextToPb(text.RegistrationOrg),
|
||||
LinkingUserPromptText: LinkingUserPromptScreenTextToPb(text.LinkingUserPrompt),
|
||||
LinkingUserDoneText: LinkingUserDoneScreenTextToPb(text.LinkingUsersDone),
|
||||
ExternalUserNotFoundText: ExternalUserNotFoundScreenTextToPb(text.ExternalNotFound),
|
||||
SuccessLoginText: SuccessLoginScreenTextToPb(text.LoginSuccess),
|
||||
@ -424,15 +423,6 @@ func LinkingUserDoneScreenTextToPb(text domain.LinkingUserDoneScreenText) *text_
|
||||
}
|
||||
}
|
||||
|
||||
func LinkingUserPromptScreenTextToPb(text domain.LinkingUserPromptScreenText) *text_pb.LinkingUserPromptScreenText {
|
||||
return &text_pb.LinkingUserPromptScreenText{
|
||||
Title: text.Title,
|
||||
Description: text.Description,
|
||||
LinkButtonText: text.LinkButtonText,
|
||||
OtherButtonText: text.OtherButtonText,
|
||||
}
|
||||
}
|
||||
|
||||
func ExternalUserNotFoundScreenTextToPb(text domain.ExternalUserNotFoundScreenText) *text_pb.ExternalUserNotFoundScreenText {
|
||||
return &text_pb.ExternalUserNotFoundScreenText{
|
||||
Title: text.Title,
|
||||
@ -902,15 +892,6 @@ func RegistrationOrgScreenTextPbToDomain(text *text_pb.RegistrationOrgScreenText
|
||||
}
|
||||
}
|
||||
|
||||
func LinkingUserPromptScreenTextPbToDomain(text *text_pb.LinkingUserPromptScreenText) domain.LinkingUserPromptScreenText {
|
||||
return domain.LinkingUserPromptScreenText{
|
||||
Title: text.GetTitle(),
|
||||
Description: text.GetDescription(),
|
||||
LinkButtonText: text.GetLinkButtonText(),
|
||||
OtherButtonText: text.GetOtherButtonText(),
|
||||
}
|
||||
}
|
||||
|
||||
func LinkingUserDoneScreenTextPbToDomain(text *text_pb.LinkingUserDoneScreenText) domain.LinkingUserDoneScreenText {
|
||||
if text == nil {
|
||||
return domain.LinkingUserDoneScreenText{}
|
||||
|
@ -1,386 +0,0 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
|
||||
func (s *Server) CreateUserSchema(ctx context.Context, req *schema.CreateUserSchemaRequest) (*schema.CreateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := createUserSchemaToCommand(req, authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, details, err := s.command.CreateUserSchema(ctx, userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.CreateUserSchemaResponse{
|
||||
Id: id,
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateUserSchema(ctx context.Context, req *schema.UpdateUserSchemaRequest) (*schema.UpdateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := updateUserSchemaToCommand(req, authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.UpdateUserSchema(ctx, userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.UpdateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeactivateUserSchema(ctx context.Context, req *schema.DeactivateUserSchemaRequest) (*schema.DeactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.DeactivateUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeactivateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateUserSchema(ctx context.Context, req *schema.ReactivateUserSchemaRequest) (*schema.ReactivateUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.ReactivateUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.ReactivateUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteUserSchema(ctx context.Context, req *schema.DeleteUserSchemaRequest) (*schema.DeleteUserSchemaResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.DeleteUserSchema(ctx, req.GetId(), authz.GetInstance(ctx).InstanceID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.DeleteUserSchemaResponse{
|
||||
Details: object.DomainToDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListUserSchemas(ctx context.Context, req *schema.ListUserSchemasRequest) (*schema.ListUserSchemasResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries, err := listUserSchemaToQuery(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.SearchUserSchema(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchemas, err := userSchemasToPb(res.UserSchemas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.ListUserSchemasResponse{
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
Result: userSchemas,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetUserSchemaByID(ctx context.Context, req *schema.GetUserSchemaByIDRequest) (*schema.GetUserSchemaByIDResponse, error) {
|
||||
if err := checkUserSchemaEnabled(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.GetUserSchemaByID(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userSchema, err := userSchemaToPb(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.GetUserSchemaByIDResponse{
|
||||
Schema: userSchema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userSchemasToPb(schemas []*query.UserSchema) (_ []*schema.UserSchema, err error) {
|
||||
userSchemas := make([]*schema.UserSchema, len(schemas))
|
||||
for i, userSchema := range schemas {
|
||||
userSchemas[i], err = userSchemaToPb(userSchema)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return userSchemas, nil
|
||||
}
|
||||
|
||||
func userSchemaToPb(userSchema *query.UserSchema) (*schema.UserSchema, error) {
|
||||
s := new(structpb.Struct)
|
||||
if err := s.UnmarshalJSON(userSchema.Schema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &schema.UserSchema{
|
||||
Id: userSchema.ID,
|
||||
Details: object.DomainToDetailsPb(&userSchema.ObjectDetails),
|
||||
Type: userSchema.Type,
|
||||
State: userSchemaStateToPb(userSchema.State),
|
||||
Revision: userSchema.Revision,
|
||||
Schema: s,
|
||||
PossibleAuthenticators: authenticatorTypesToPb(userSchema.PossibleAuthenticators),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorTypesToPb(authenticators []domain.AuthenticatorType) []schema.AuthenticatorType {
|
||||
authTypes := make([]schema.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
authTypes[i] = authenticatorTypeToPb(authenticator)
|
||||
}
|
||||
return authTypes
|
||||
}
|
||||
|
||||
func authenticatorTypeToPb(authenticator domain.AuthenticatorType) schema.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case domain.AuthenticatorTypeUsername:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME
|
||||
case domain.AuthenticatorTypePassword:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD
|
||||
case domain.AuthenticatorTypeWebAuthN:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN
|
||||
case domain.AuthenticatorTypeTOTP:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP
|
||||
case domain.AuthenticatorTypeOTPEmail:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL
|
||||
case domain.AuthenticatorTypeOTPSMS:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS
|
||||
case domain.AuthenticatorTypeAuthenticationKey:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY
|
||||
case domain.AuthenticatorTypeIdentityProvider:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER
|
||||
case domain.AuthenticatorTypeUnspecified:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
default:
|
||||
return schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToPb(state domain.UserSchemaState) schema.State {
|
||||
switch state {
|
||||
case domain.UserSchemaStateActive:
|
||||
return schema.State_STATE_ACTIVE
|
||||
case domain.UserSchemaStateInactive:
|
||||
return schema.State_STATE_INACTIVE
|
||||
case domain.UserSchemaStateUnspecified,
|
||||
domain.UserSchemaStateDeleted:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
default:
|
||||
return schema.State_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func listUserSchemaToQuery(req *schema.ListUserSchemasRequest) (*query.UserSchemaSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||
queries, err := userSchemaQueriesToQuery(req.Queries, 0) // start at level 0
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.UserSchemaSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: userSchemaFieldNameToSortingColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userSchemaFieldNameToSortingColumn(column schema.FieldName) query.Column {
|
||||
switch column {
|
||||
case schema.FieldName_FIELD_NAME_TYPE:
|
||||
return query.UserSchemaTypeCol
|
||||
case schema.FieldName_FIELD_NAME_STATE:
|
||||
return query.UserSchemaStateCol
|
||||
case schema.FieldName_FIELD_NAME_REVISION:
|
||||
return query.UserSchemaRevisionCol
|
||||
case schema.FieldName_FIELD_NAME_CHANGE_DATE:
|
||||
return query.UserSchemaChangeDateCol
|
||||
case schema.FieldName_FIELD_NAME_UNSPECIFIED:
|
||||
return query.UserSchemaIDCol
|
||||
default:
|
||||
return query.UserSchemaIDCol
|
||||
}
|
||||
}
|
||||
|
||||
func checkUserSchemaEnabled(ctx context.Context) error {
|
||||
if authz.GetInstance(ctx).Features().UserSchema {
|
||||
return nil
|
||||
}
|
||||
return zerrors.ThrowPreconditionFailed(nil, "SCHEMA-SFjk3", "Errors.UserSchema.NotEnabled")
|
||||
}
|
||||
|
||||
func createUserSchemaToCommand(req *schema.CreateUserSchemaRequest, resourceOwner string) (*command.CreateUserSchema, error) {
|
||||
schema, err := req.GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.CreateUserSchema{
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: req.GetType(),
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func updateUserSchemaToCommand(req *schema.UpdateUserSchemaRequest, resourceOwner string) (*command.UpdateUserSchema, error) {
|
||||
schema, err := req.GetSchema().MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &command.UpdateUserSchema{
|
||||
ID: req.GetId(),
|
||||
ResourceOwner: resourceOwner,
|
||||
Type: req.Type,
|
||||
Schema: schema,
|
||||
PossibleAuthenticators: authenticatorsToDomain(req.GetPossibleAuthenticators()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func authenticatorsToDomain(authenticators []schema.AuthenticatorType) []domain.AuthenticatorType {
|
||||
types := make([]domain.AuthenticatorType, len(authenticators))
|
||||
for i, authenticator := range authenticators {
|
||||
types[i] = authenticatorTypeToDomain(authenticator)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
func authenticatorTypeToDomain(authenticator schema.AuthenticatorType) domain.AuthenticatorType {
|
||||
switch authenticator {
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_UNSPECIFIED:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_USERNAME:
|
||||
return domain.AuthenticatorTypeUsername
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_PASSWORD:
|
||||
return domain.AuthenticatorTypePassword
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_WEBAUTHN:
|
||||
return domain.AuthenticatorTypeWebAuthN
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_TOTP:
|
||||
return domain.AuthenticatorTypeTOTP
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_EMAIL:
|
||||
return domain.AuthenticatorTypeOTPEmail
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_OTP_SMS:
|
||||
return domain.AuthenticatorTypeOTPSMS
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_AUTHENTICATION_KEY:
|
||||
return domain.AuthenticatorTypeAuthenticationKey
|
||||
case schema.AuthenticatorType_AUTHENTICATOR_TYPE_IDENTITY_PROVIDER:
|
||||
return domain.AuthenticatorTypeIdentityProvider
|
||||
default:
|
||||
return domain.AuthenticatorTypeUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaStateToDomain(state schema.State) domain.UserSchemaState {
|
||||
switch state {
|
||||
case schema.State_STATE_ACTIVE:
|
||||
return domain.UserSchemaStateActive
|
||||
case schema.State_STATE_INACTIVE:
|
||||
return domain.UserSchemaStateInactive
|
||||
case schema.State_STATE_UNSPECIFIED:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
default:
|
||||
return domain.UserSchemaStateUnspecified
|
||||
}
|
||||
}
|
||||
|
||||
func userSchemaQueriesToQuery(queries []*schema.SearchQuery, level uint8) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = userSchemaQueryToQuery(query, level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func userSchemaQueryToQuery(query *schema.SearchQuery, level uint8) (query.SearchQuery, error) {
|
||||
if level > 20 {
|
||||
// can't go deeper than 20 levels of nesting.
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-zsQ97", "Errors.Query.TooManyNestingLevels")
|
||||
}
|
||||
switch q := query.Query.(type) {
|
||||
case *schema.SearchQuery_StateQuery:
|
||||
return stateQueryToQuery(q.StateQuery)
|
||||
case *schema.SearchQuery_TypeQuery:
|
||||
return typeQueryToQuery(q.TypeQuery)
|
||||
case *schema.SearchQuery_IdQuery:
|
||||
return idQueryToQuery(q.IdQuery)
|
||||
case *schema.SearchQuery_OrQuery:
|
||||
return orQueryToQuery(q.OrQuery, level)
|
||||
case *schema.SearchQuery_AndQuery:
|
||||
return andQueryToQuery(q.AndQuery, level)
|
||||
case *schema.SearchQuery_NotQuery:
|
||||
return notQueryToQuery(q.NotQuery, level)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SCHEMA-vR9nC", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func stateQueryToQuery(q *schema.StateQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaStateSearchQuery(userSchemaStateToDomain(q.GetState()))
|
||||
}
|
||||
|
||||
func typeQueryToQuery(q *schema.TypeQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaTypeSearchQuery(q.GetType(), object.TextMethodToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func idQueryToQuery(q *schema.IDQuery) (query.SearchQuery, error) {
|
||||
return query.NewUserSchemaIDSearchQuery(q.GetId(), object.TextMethodToQuery(q.GetMethod()))
|
||||
}
|
||||
|
||||
func orQueryToQuery(q *schema.OrQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaQueriesToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserOrSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func andQueryToQuery(q *schema.AndQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQueries, err := userSchemaQueriesToQuery(q.GetQueries(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserAndSearchQuery(mappedQueries)
|
||||
}
|
||||
|
||||
func notQueryToQuery(q *schema.NotQuery, level uint8) (query.SearchQuery, error) {
|
||||
mappedQuery, err := userSchemaQueryToQuery(q.GetQuery(), level+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return query.NewUserNotSearchQuery(mappedQuery)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
schema "github.com/zitadel/zitadel/pkg/grpc/user/schema/v3alpha"
|
||||
)
|
||||
|
||||
var _ schema.UserSchemaServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
schema.UnimplementedUserSchemaServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
schema.RegisterUserSchemaServiceServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return schema.UserSchemaService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return schema.UserSchemaService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return schema.UserSchemaService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return schema.RegisterUserSchemaServiceHandler
|
||||
}
|
@ -30,11 +30,10 @@ func (s *Server) ListIDPLinks(ctx context.Context, req *user.ListIDPLinksRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.query.IDPUserLinks(ctx, queries, false)
|
||||
res, err := s.query.IDPUserLinks(ctx, queries, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.RemoveNoPermission(ctx, s.checkPermission)
|
||||
return &user.ListIDPLinksResponse{
|
||||
Result: IDPLinksToPb(res.Links),
|
||||
Details: object.ToListDetails(res.SearchResponse),
|
||||
|
@ -122,6 +122,16 @@ func TestServer_ListIDPLinks(t *testing.T) {
|
||||
want *user.ListIDPLinksResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "list links, missing userID",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&user.ListIDPLinksRequest{
|
||||
UserId: "",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list links, no permission",
|
||||
args: args{
|
||||
@ -130,13 +140,7 @@ func TestServer_ListIDPLinks(t *testing.T) {
|
||||
UserId: userOrgResp.GetUserId(),
|
||||
},
|
||||
},
|
||||
want: &user.ListIDPLinksResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
Result: []*user.IDPLink{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list links, no permission, org",
|
||||
@ -146,13 +150,7 @@ func TestServer_ListIDPLinks(t *testing.T) {
|
||||
UserId: userOrgResp.GetUserId(),
|
||||
},
|
||||
},
|
||||
want: &user.ListIDPLinksResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
Result: []*user.IDPLink{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list idp links, org, ok",
|
||||
|
@ -142,8 +142,7 @@ func (s *Server) ListPasskeys(ctx context.Context, req *user.ListPasskeysRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, false)
|
||||
authMethods.RemoveNoPermission(ctx, s.checkPermission)
|
||||
authMethods, err := s.query.SearchUserAuthMethods(ctx, query, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -471,6 +471,16 @@ func TestServer_ListPasskeys(t *testing.T) {
|
||||
want *user.ListPasskeysResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "list passkeys, no userID",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&user.ListPasskeysRequest{
|
||||
UserId: "",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list passkeys, no permission",
|
||||
args: args{
|
||||
@ -479,18 +489,12 @@ func TestServer_ListPasskeys(t *testing.T) {
|
||||
UserId: userIDVerified,
|
||||
},
|
||||
},
|
||||
want: &user.ListPasskeysResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
Timestamp: timestamppb.Now(),
|
||||
},
|
||||
Result: []*user.Passkey{},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "list passkeys, none",
|
||||
args: args{
|
||||
UserCTX,
|
||||
IamCTX,
|
||||
&user.ListPasskeysRequest{
|
||||
UserId: userIDWithout,
|
||||
},
|
||||
@ -506,7 +510,7 @@ func TestServer_ListPasskeys(t *testing.T) {
|
||||
{
|
||||
name: "list passkeys, registered",
|
||||
args: args{
|
||||
UserCTX,
|
||||
IamCTX,
|
||||
&user.ListPasskeysRequest{
|
||||
UserId: userIDRegistered,
|
||||
},
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -15,15 +14,10 @@ import (
|
||||
)
|
||||
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest) (_ *user.GetUserByIDResponse, err error) {
|
||||
resp, err := s.query.GetUserByID(ctx, true, req.GetUserId())
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.GetUserId(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if authz.GetCtxData(ctx).UserID != req.GetUserId() {
|
||||
if err := s.checkPermission(ctx, domain.PermissionUserRead, resp.ResourceOwner, req.GetUserId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &user.GetUserByIDResponse{
|
||||
Details: object.DomainToDetailsPb(&domain.ObjectDetails{
|
||||
Sequence: resp.Sequence,
|
||||
|
@ -421,7 +421,7 @@ func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUse
|
||||
queries := []query.SearchQuery{
|
||||
idQuery, externalIDQuery,
|
||||
}
|
||||
links, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, false)
|
||||
links, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -15,15 +14,10 @@ import (
|
||||
)
|
||||
|
||||
func (s *Server) GetUserByID(ctx context.Context, req *user.GetUserByIDRequest) (_ *user.GetUserByIDResponse, err error) {
|
||||
resp, err := s.query.GetUserByID(ctx, true, req.GetUserId())
|
||||
resp, err := s.query.GetUserByIDWithPermission(ctx, true, req.GetUserId(), s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if authz.GetCtxData(ctx).UserID != req.GetUserId() {
|
||||
if err := s.checkPermission(ctx, domain.PermissionUserRead, resp.ResourceOwner, req.GetUserId()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &user.GetUserByIDResponse{
|
||||
Details: object.DomainToDetailsPb(&domain.ObjectDetails{
|
||||
Sequence: resp.Sequence,
|
||||
|
@ -434,7 +434,7 @@ func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUse
|
||||
queries := []query.SearchQuery{
|
||||
idQuery, externalIDQuery,
|
||||
}
|
||||
links, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, false)
|
||||
links, err := s.query.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -108,6 +108,11 @@ func (c *Cache) serializeHeaders(w http.ResponseWriter) {
|
||||
control := make([]string, 0, 6)
|
||||
pragma := false
|
||||
|
||||
// Do not overwrite cache-control header if set by business logic.
|
||||
if w.Header().Get(http_utils.CacheControl) != "" {
|
||||
return
|
||||
}
|
||||
|
||||
if c.Cacheability != CacheabilityNotSet {
|
||||
control = append(control, string(c.Cacheability))
|
||||
control = append(control, fmt.Sprintf("max-age=%v", c.MaxAge.Seconds()))
|
||||
|
@ -420,7 +420,7 @@ func (h *Handler) checkExternalUser(ctx context.Context, idpID, externalUserID s
|
||||
queries := []query.SearchQuery{
|
||||
idQuery, externalIDQuery,
|
||||
}
|
||||
links, err := h.queries.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, false)
|
||||
links, err := h.queries.IDPUserLinks(ctx, &query.IDPUserLinksSearchQuery{Queries: queries}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -52,7 +52,9 @@ func (s *Server) verifyAccessToken(ctx context.Context, tkn string) (_ *accessTo
|
||||
}
|
||||
tokenID, subject = split[0], split[1]
|
||||
} else {
|
||||
verifier := op.NewAccessTokenVerifier(op.IssuerFromContext(ctx), s.accessTokenKeySet)
|
||||
verifier := op.NewAccessTokenVerifier(op.IssuerFromContext(ctx), s.accessTokenKeySet,
|
||||
op.WithSupportedAccessTokenSigningAlgorithms(supportedSigningAlgs(ctx)...),
|
||||
)
|
||||
claims, err := op.VerifyAccessToken[*oidc.AccessTokenClaims](ctx, tkn, verifier)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPermissionDenied(err, "OIDC-Eib8e", "token is not valid or has expired")
|
||||
|
@ -277,7 +277,7 @@ func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID str
|
||||
if zerrors.IsPreconditionFailed(err) {
|
||||
return oidc.ErrInvalidClient().WithDescription("token was not issued for this client")
|
||||
}
|
||||
return oidc.ErrServerError().WithParent(err)
|
||||
return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError)
|
||||
}
|
||||
|
||||
return o.revokeTokenV1(ctx, token, userID, clientID)
|
||||
@ -293,14 +293,14 @@ func (o *OPStorage) revokeTokenV1(ctx context.Context, token, userID, clientID s
|
||||
if err == nil || zerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return oidc.ErrServerError().WithParent(err)
|
||||
return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError)
|
||||
}
|
||||
accessToken, err := o.repo.TokenByIDs(ctx, userID, token)
|
||||
if err != nil {
|
||||
if zerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return oidc.ErrServerError().WithParent(err)
|
||||
return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError)
|
||||
}
|
||||
if accessToken.ApplicationID != clientID {
|
||||
return oidc.ErrInvalidClient().WithDescription("token was not issued for this client")
|
||||
@ -309,7 +309,7 @@ func (o *OPStorage) revokeTokenV1(ctx context.Context, token, userID, clientID s
|
||||
if err == nil || zerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return oidc.ErrServerError().WithParent(err)
|
||||
return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError)
|
||||
}
|
||||
|
||||
func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, token string) (userID string, tokenID string, err error) {
|
||||
|
@ -975,13 +975,13 @@ func (s *Server) VerifyClient(ctx context.Context, r *op.Request[op.ClientCreden
|
||||
return s.clientCredentialsAuth(ctx, r.Data.ClientID, r.Data.ClientSecret)
|
||||
}
|
||||
|
||||
clientID, assertion, err := clientIDFromCredentials(r.Data)
|
||||
clientID, assertion, err := clientIDFromCredentials(ctx, r.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := s.query.GetOIDCClientByID(ctx, clientID, assertion)
|
||||
if zerrors.IsNotFound(err) {
|
||||
return nil, oidc.ErrInvalidClient().WithParent(err).WithDescription("client not found")
|
||||
return nil, oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("client not found")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err // defaults to server error
|
||||
@ -1019,7 +1019,7 @@ func (s *Server) verifyClientAssertion(ctx context.Context, client *query.OIDCCl
|
||||
}
|
||||
verifier := op.NewJWTProfileVerifierKeySet(keySetMap(client.PublicKeys), op.IssuerFromContext(ctx), time.Hour, client.ClockSkew)
|
||||
if _, err := op.VerifyJWTAssertion(ctx, assertion, verifier); err != nil {
|
||||
return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid assertion")
|
||||
return oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("invalid assertion")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1035,10 +1035,11 @@ func (s *Server) verifyClientSecret(ctx context.Context, client *query.OIDCClien
|
||||
updated, err := s.hasher.Verify(client.HashedSecret, secret)
|
||||
spanPasswordComparison.EndWithError(err)
|
||||
if err != nil {
|
||||
s.command.OIDCSecretCheckFailed(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner)
|
||||
return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid secret")
|
||||
return oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("invalid secret")
|
||||
}
|
||||
if updated != "" {
|
||||
s.command.OIDCUpdateSecret(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner, updated)
|
||||
}
|
||||
s.command.OIDCSecretCheckSucceeded(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner, updated)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
@ -8,6 +9,7 @@ import (
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -218,11 +220,11 @@ func removeScopeWithPrefix(scopes []string, scopePrefix ...string) []string {
|
||||
return newScopeList
|
||||
}
|
||||
|
||||
func clientIDFromCredentials(cc *op.ClientCredentials) (clientID string, assertion bool, err error) {
|
||||
func clientIDFromCredentials(ctx context.Context, cc *op.ClientCredentials) (clientID string, assertion bool, err error) {
|
||||
if cc.ClientAssertion != "" {
|
||||
claims := new(oidc.JWTTokenRequest)
|
||||
if _, err := oidc.ParseToken(cc.ClientAssertion, claims); err != nil {
|
||||
return "", false, oidc.ErrInvalidClient().WithParent(err)
|
||||
return "", false, oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError)
|
||||
}
|
||||
return claims.Issuer, true, nil
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user