feat: add domain verification notification (#649)

* fix: dont (re)generate client secret with auth type none

* fix(cors): allow Origin from request

* feat: add origin allow list and fix some core issues

* rename migration

* fix UserIDsByDomain

* feat: send email to users after domain claim

* username

* check origin on userinfo

* update oidc pkg

* fix: add migration 1.6

* change username

* change username

* remove unique email aggregate

* change username in mgmt

* search global user by login name

* fix test

* change user search in angular

* fix tests

* merge

* userview in angular

* fix merge

* Update pkg/grpc/management/proto/management.proto

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* Update internal/notification/static/i18n/de.yaml

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* fix

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
Livio Amstutz 2020-08-27 17:18:23 +02:00 committed by GitHub
parent 3f714679d1
commit 34ec2508d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 19105 additions and 17845 deletions

View File

@ -23,6 +23,7 @@ InternalAuthZ:
- "org.idp.write" - "org.idp.write"
- "org.idp.delete" - "org.idp.delete"
- "user.read" - "user.read"
- "user.global.read"
- "user.write" - "user.write"
- "user.delete" - "user.delete"
- "user.grant.read" - "user.grant.read"
@ -66,6 +67,7 @@ InternalAuthZ:
- "org.member.read" - "org.member.read"
- "org.idp.read" - "org.idp.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.membership.read" - "user.membership.read"
- "policy.read" - "policy.read"
@ -89,6 +91,7 @@ InternalAuthZ:
- "org.idp.write" - "org.idp.write"
- "org.idp.delete" - "org.idp.delete"
- "user.read" - "user.read"
- "user.global.read"
- "user.write" - "user.write"
- "user.delete" - "user.delete"
- "user.grant.read" - "user.grant.read"
@ -127,6 +130,7 @@ InternalAuthZ:
- "org.member.read" - "org.member.read"
- "org.idp.read" - "org.idp.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.membership.read" - "user.membership.read"
- "policy.read" - "policy.read"
@ -143,6 +147,7 @@ InternalAuthZ:
- "org.read" - "org.read"
- "org.member.read" - "org.member.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.grant.write" - "user.grant.write"
- "user.grant.delete" - "user.grant.delete"
@ -158,6 +163,7 @@ InternalAuthZ:
- "org.read" - "org.read"
- "org.member.read" - "org.member.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.grant.write" - "user.grant.write"
- "user.grant.delete" - "user.grant.delete"
@ -172,6 +178,7 @@ InternalAuthZ:
- "project.grant.member.read" - "project.grant.member.read"
- Role: 'ORG_PROJECT_CREATOR' - Role: 'ORG_PROJECT_CREATOR'
Permissions: Permissions:
- "user.global.read"
- "project.read:self" - "project.read:self"
- "project.write" - "project.write"
- Role: 'PROJECT_OWNER' - Role: 'PROJECT_OWNER'
@ -195,6 +202,7 @@ InternalAuthZ:
- "project.grant.member.write" - "project.grant.member.write"
- "project.grant.member.delete" - "project.grant.member.delete"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.grant.write" - "user.grant.write"
- "user.grant.delete" - "user.grant.delete"
@ -208,6 +216,7 @@ InternalAuthZ:
- "project.grant.read" - "project.grant.read"
- "project.grant.member.read" - "project.grant.member.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.membership.read" - "user.membership.read"
- Role: 'PROJECT_GRANT_OWNER' - Role: 'PROJECT_GRANT_OWNER'
@ -218,6 +227,7 @@ InternalAuthZ:
- "project.grant.member.write" - "project.grant.member.write"
- "project.grant.member.delete" - "project.grant.member.delete"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.grant.write" - "user.grant.write"
- "user.grant.delete" - "user.grant.delete"
@ -228,5 +238,6 @@ InternalAuthZ:
- "project.grant.read" - "project.grant.read"
- "project.grant.member.read" - "project.grant.member.read"
- "user.read" - "user.read"
- "user.global.read"
- "user.grant.read" - "user.grant.read"
- "user.membership.read" - "user.membership.read"

View File

@ -89,6 +89,7 @@ SystemDefaults:
InitCode: '$ZITADEL_ACCOUNTS/user/init?userID={{.UserID}}&code={{.Code}}&passwordset={{.PasswordSet}}' InitCode: '$ZITADEL_ACCOUNTS/user/init?userID={{.UserID}}&code={{.Code}}&passwordset={{.PasswordSet}}'
PasswordReset: '$ZITADEL_ACCOUNTS/password/init?userID={{.UserID}}&code={{.Code}}' PasswordReset: '$ZITADEL_ACCOUNTS/password/init?userID={{.UserID}}&code={{.Code}}'
VerifyEmail: '$ZITADEL_ACCOUNTS/mail/verification?userID={{.UserID}}&code={{.Code}}' VerifyEmail: '$ZITADEL_ACCOUNTS/mail/verification?userID={{.UserID}}&code={{.Code}}'
DomainClaimed: '$ZITADEL_ACCOUNTS/login'
Providers: Providers:
Chat: Chat:
Url: $CHAT_URL Url: $CHAT_URL
@ -133,4 +134,11 @@ SystemDefaults:
Subject: 'VerifyPhone.Subject' Subject: 'VerifyPhone.Subject'
Greeting: 'VerifyPhone.Greeting' Greeting: 'VerifyPhone.Greeting'
Text: 'VerifyPhone.Text' Text: 'VerifyPhone.Text'
ButtonText: 'VerifyPhone.ButtonText' ButtonText: 'VerifyPhone.ButtonText'
DomainClaimed:
Title: 'DomainClaimed.Title'
PreHeader: 'DomainClaimed.PreHeader'
Subject: 'DomainClaimed.Subject'
Greeting: 'DomainClaimed.Greeting'
Text: 'DomainClaimed.Text'
ButtonText: 'DomainClaimed.ButtonText'

2715
console/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { ProjectGrantView, ProjectRole, ProjectView, User } from 'src/app/proto/generated/management_pb'; import { ProjectGrantView, ProjectRole, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@ -21,7 +21,7 @@ export enum CreationType {
export class MemberCreateDialogComponent { export class MemberCreateDialogComponent {
private projectId: string = ''; private projectId: string = '';
private grantId: string = ''; private grantId: string = '';
public preselectedUsers: Array<User.AsObject> = []; public preselectedUsers: Array<UserView.AsObject> = [];
public creationType!: CreationType; public creationType!: CreationType;
@ -31,7 +31,7 @@ export class MemberCreateDialogComponent {
CreationType.PROJECT_OWNED, CreationType.PROJECT_OWNED,
CreationType.PROJECT_GRANTED, CreationType.PROJECT_GRANTED,
]; ];
public users: Array<User.AsObject> = []; public users: Array<UserView.AsObject> = [];
public roles: Array<ProjectRole.AsObject> | string[] = []; public roles: Array<ProjectRole.AsObject> | string[] = [];
public CreationType: any = CreationType; public CreationType: any = CreationType;
public ProjectAutocompleteType: any = ProjectAutocompleteType; public ProjectAutocompleteType: any = ProjectAutocompleteType;

View File

@ -6,7 +6,7 @@ import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table'; import { MatTable } from '@angular/material/table';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { ProjectGrantView, ProjectMember, ProjectType, ProjectView, User } from 'src/app/proto/generated/management_pb'; import { ProjectGrantView, ProjectMember, ProjectType, ProjectView, UserView } from 'src/app/proto/generated/management_pb';
import { ProjectService } from 'src/app/services/project.service'; import { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@ -128,7 +128,7 @@ export class ProjectMembersComponent {
dialogRef.afterClosed().subscribe(resp => { dialogRef.afterClosed().subscribe(resp => {
if (resp) { if (resp) {
const users: User.AsObject[] = resp.users; const users: UserView.AsObject[] = resp.users;
const roles: string[] = resp.roles; const roles: string[] = resp.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {

View File

@ -1,17 +1,17 @@
<form> <form>
<mat-form-field *ngIf="target == UserTarget.SELF" appearance="outline" class="full-width"> <mat-form-field *ngIf="target == UserTarget.SELF" appearance="outline" class="full-width">
<mat-label>Organizations User Email</mat-label> <mat-label>Organizations User Loginname</mat-label>
<input matInput *ngIf="singleOutput" type="text" placeholder="Search for the user email" #usernameInput <input matInput *ngIf="singleOutput" type="text" placeholder="Search for the user loginname" #usernameInput
[formControl]="myControl" [matAutocomplete]="auto" /> [formControl]="myControl" [matAutocomplete]="auto" />
<mat-chip-list *ngIf="!singleOutput" #chipList aria-label="useremail selection"> <mat-chip-list *ngIf="!singleOutput" #chipList aria-label="loginname selection">
<mat-chip class="chip" *ngFor="let selecteduser of users" [selectable]="selectable" [removable]="removable" <mat-chip class="chip" *ngFor="let selecteduser of users" [selectable]="selectable" [removable]="removable"
(removed)="remove(selecteduser)"> (removed)="remove(selecteduser)">
{{ selecteduser?.firstName }} {{selecteduser.lastName}} | <small> {{selecteduser.email}}</small> {{ selecteduser?.firstName }} {{selecteduser.lastName}} | <small> {{selecteduser.preferredLoginName}}</small>
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon> <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
</mat-chip> </mat-chip>
<input placeholder="{{'ORG_DETAIL.MEMBER.EMAIL' | translate}}" #usernameInput [formControl]="myControl" <input placeholder="{{'ORG_DETAIL.MEMBER.LOGINNAME' | translate}}" #usernameInput [formControl]="myControl"
[matAutocomplete]="auto" [matChipInputFor]="chipList" [matAutocomplete]="auto" [matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)" /> (matChipInputTokenEnd)="add($event)" />
@ -23,15 +23,15 @@
</mat-option> </mat-option>
<mat-option *ngFor="let user of filteredUsers" [value]="user"> <mat-option *ngFor="let user of filteredUsers" [value]="user">
{{user.firstName}} {{user.lastName}} {{user.firstName}} {{user.lastName}}
<small>{{user.email}}</small> <small>{{user.preferredLoginName}}</small>
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>
</mat-form-field> </mat-form-field>
<div *ngIf="target == UserTarget.EXTERNAL" class="line"> <div *ngIf="target == UserTarget.EXTERNAL" class="line">
<mat-form-field class="form-field" appearance="outline"> <mat-form-field class="form-field" appearance="outline">
<mat-label>Global User Email</mat-label> <mat-label>Global User Loginname</mat-label>
<input matInput type="text" [formControl]="globalEmailControl" /> <input matInput type="text" [formControl]="globalLoginNameControl" />
</mat-form-field> </mat-form-field>
<button color="primary" mat-icon-button (click)="getGlobalUser()"> <button color="primary" mat-icon-button (click)="getGlobalUser()">
@ -42,7 +42,7 @@
<div *ngIf="target == UserTarget.EXTERNAL && users.length > 0"> <div *ngIf="target == UserTarget.EXTERNAL && users.length > 0">
<span class="found-label">{{'USER.SEARCH.FOUND' | translate}}:</span> <span class="found-label">{{'USER.SEARCH.FOUND' | translate}}:</span>
<div class="found-user-row" *ngFor="let user of users; index as i"> <div class="found-user-row" *ngFor="let user of users; index as i">
<span>{{user.email}}</span> <span>{{user.preferredLoginName}}</span>
<button mat-icon-button> <button mat-icon-button>
<i class="las la-minus-circle" (click)="users.splice(i, 1)"></i> <i class="las la-minus-circle" (click)="users.splice(i, 1)"></i>
</button> </button>
@ -52,4 +52,4 @@
<p class="target-desc">{{(target == UserTarget.SELF ? 'USER.TARGET.SELF' : 'USER.TARGET.EXTERNAL') | translate}} <p class="target-desc">{{(target == UserTarget.SELF ? 'USER.TARGET.SELF' : 'USER.TARGET.EXTERNAL') | translate}}
<a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a> <a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a>
</p> </p>
</form> </form>

View File

@ -5,7 +5,7 @@ import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material
import { MatChipInputEvent } from '@angular/material/chips'; import { MatChipInputEvent } from '@angular/material/chips';
import { from, of, Subject } from 'rxjs'; import { from, of, Subject } from 'rxjs';
import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators'; import { debounceTime, switchMap, takeUntil, tap } from 'rxjs/operators';
import { SearchMethod, User, UserSearchKey, UserSearchQuery } from 'src/app/proto/generated/management_pb'; import { SearchMethod, UserView, UserSearchKey, UserSearchQuery } from 'src/app/proto/generated/management_pb';
import { MgmtUserService } from 'src/app/services/mgmt-user.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
@ -26,18 +26,18 @@ export class SearchUserAutocompleteComponent {
public separatorKeysCodes: number[] = [ENTER, COMMA]; public separatorKeysCodes: number[] = [ENTER, COMMA];
public myControl: FormControl = new FormControl(); public myControl: FormControl = new FormControl();
public globalEmailControl: FormControl = new FormControl(); public globalLoginNameControl: FormControl = new FormControl();
public emails: string[] = []; public loginNames: string[] = [];
@Input() public users: Array<User.AsObject> = []; @Input() public users: Array<UserView.AsObject> = [];
public filteredUsers: Array<User.AsObject> = []; public filteredUsers: Array<UserView.AsObject> = [];
public isLoading: boolean = false; public isLoading: boolean = false;
public target: UserTarget = UserTarget.SELF; public target: UserTarget = UserTarget.SELF;
public hint: string = ''; public hint: string = '';
public UserTarget: any = UserTarget; public UserTarget: any = UserTarget;
@ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>; @ViewChild('usernameInput') public usernameInput!: ElementRef<HTMLInputElement>;
@ViewChild('auto') public matAutocomplete!: MatAutocomplete; @ViewChild('auto') public matAutocomplete!: MatAutocomplete;
@Output() public selectionChanged: EventEmitter<User.AsObject | User.AsObject[]> = new EventEmitter(); @Output() public selectionChanged: EventEmitter<UserView.AsObject | UserView.AsObject[]> = new EventEmitter();
@Input() public singleOutput: boolean = false; @Input() public singleOutput: boolean = false;
private unsubscribed$: Subject<void> = new Subject(); private unsubscribed$: Subject<void> = new Subject();
@ -51,7 +51,7 @@ export class SearchUserAutocompleteComponent {
tap(() => this.isLoading = true), tap(() => this.isLoading = true),
switchMap(value => { switchMap(value => {
const query = new UserSearchQuery(); const query = new UserSearchQuery();
query.setKey(UserSearchKey.USERSEARCHKEY_EMAIL); query.setKey(UserSearchKey.USERSEARCHKEY_USER_NAME);
query.setValue(value); query.setValue(value);
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE); query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
if (this.target === UserTarget.SELF) { if (this.target === UserTarget.SELF) {
@ -68,8 +68,8 @@ export class SearchUserAutocompleteComponent {
}); });
} }
public displayFn(user?: User.AsObject): string | undefined { public displayFn(user?: UserView.AsObject): string | undefined {
return user ? `${user.email}` : undefined; return user ? `${user.preferredLoginName}` : undefined;
} }
public add(event: MatChipInputEvent): void { public add(event: MatChipInputEvent): void {
@ -79,8 +79,8 @@ export class SearchUserAutocompleteComponent {
if ((value || '').trim()) { if ((value || '').trim()) {
const index = this.filteredUsers.findIndex((user) => { const index = this.filteredUsers.findIndex((user) => {
if (user.email) { if (user.preferredLoginName) {
return user.email === value; return user.preferredLoginName === value;
} }
}); });
if (index > -1) { if (index > -1) {
@ -98,7 +98,7 @@ export class SearchUserAutocompleteComponent {
} }
} }
public remove(user: User.AsObject): void { public remove(user: UserView.AsObject): void {
const index = this.users.indexOf(user); const index = this.users.indexOf(user);
if (index >= 0) { if (index >= 0) {
@ -138,7 +138,7 @@ export class SearchUserAutocompleteComponent {
} }
public getGlobalUser(): void { public getGlobalUser(): void {
this.userService.GetUserByEmailGlobal(this.globalEmailControl.value).then(user => { this.userService.GetUserByLoginNameGlobal(this.globalLoginNameControl.value).then(user => {
this.users = [user.toObject()]; this.users = [user.toObject()];
this.selectionChanged.emit(this.users); this.selectionChanged.emit(this.users);
}).catch(error => { }).catch(error => {

View File

@ -22,7 +22,7 @@ import {
ProjectState, ProjectState,
ProjectType, ProjectType,
ProjectView, ProjectView,
User, UserView,
UserGrantSearchKey, UserGrantSearchKey,
} from 'src/app/proto/generated/management_pb'; } from 'src/app/proto/generated/management_pb';
import { OrgService } from 'src/app/services/org.service'; import { OrgService } from 'src/app/services/org.service';
@ -216,7 +216,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => { dialogRef.afterClosed().subscribe(resp => {
if (resp) { if (resp) {
const users: User.AsObject[] = resp.users; const users: UserView.AsObject[] = resp.users;
const roles: string[] = resp.roles; const roles: string[] = resp.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {

View File

@ -3,7 +3,7 @@ import { Component, Input, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component'; import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
import { MemberType, User, UserMembershipSearchResponse } from 'src/app/proto/generated/management_pb'; import { MemberType, UserView, UserMembershipSearchResponse } from 'src/app/proto/generated/management_pb';
import { AdminService } from 'src/app/services/admin.service'; import { AdminService } from 'src/app/services/admin.service';
import { MgmtUserService } from 'src/app/services/mgmt-user.service'; import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { OrgService } from 'src/app/services/org.service'; import { OrgService } from 'src/app/services/org.service';
@ -35,7 +35,7 @@ export class MembershipsComponent implements OnInit {
public loading: boolean = false; public loading: boolean = false;
public memberships!: UserMembershipSearchResponse.AsObject; public memberships!: UserMembershipSearchResponse.AsObject;
@Input() public user!: User.AsObject; @Input() public user!: UserView.AsObject;
public MemberType: any = MemberType; public MemberType: any = MemberType;
constructor( constructor(
@ -92,7 +92,7 @@ export class MembershipsComponent implements OnInit {
} }
public createIamMember(response: any): void { public createIamMember(response: any): void {
const users: User.AsObject[] = response.users; const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles; const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {
@ -107,7 +107,7 @@ export class MembershipsComponent implements OnInit {
} }
private createOrgMember(response: any): void { private createOrgMember(response: any): void {
const users: User.AsObject[] = response.users; const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles; const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {
@ -122,7 +122,7 @@ export class MembershipsComponent implements OnInit {
} }
private createGrantedProjectMember(response: any): void { private createGrantedProjectMember(response: any): void {
const users: User.AsObject[] = response.users; const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles; const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {
@ -142,7 +142,7 @@ export class MembershipsComponent implements OnInit {
} }
private createOwnedProjectMember(response: any): void { private createOwnedProjectMember(response: any): void {
const users: User.AsObject[] = response.users; const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles; const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) { if (users && users.length && roles && roles.length) {

View File

@ -7,7 +7,7 @@ import {
ChangeRequest, ChangeRequest,
Changes, Changes,
CreateUserRequest, CreateUserRequest,
Email, LoginName,
Gender, Gender,
MultiFactors, MultiFactors,
NotificationType, NotificationType,
@ -391,11 +391,11 @@ export class MgmtUserService {
); );
} }
public async GetUserByEmailGlobal(email: string): Promise<User> { public async GetUserByLoginNameGlobal(loginName: string): Promise<UserView> {
const req = new Email(); const req = new LoginName();
req.setEmail(email); req.setLoginName(loginName);
return await this.request( return await this.request(
c => c.getUserByEmailGlobal, c => c.getUserByLoginNameGlobal,
req, req,
f => f, f => f,
); );

2
go.sum
View File

@ -44,8 +44,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=

View File

@ -80,7 +80,8 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
return err return err
} }
err = user.AppendEvent(event) err = user.AppendEvent(event)
case es_model.DomainClaimed: case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID) user, err = u.view.UserByID(event.AggregateID)
if err != nil { if err != nil {
return err return err

View File

@ -19,8 +19,8 @@ func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserV
return view.SearchUsers(v.Db, userTable, request) return view.SearchUsers(v.Db, userTable, request)
} }
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) { func (v *View) GetGlobalUserByLoginName(loginName string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email) return view.GetGlobalUserByLoginName(v.Db, userTable, loginName)
} }
func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) { func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) {

View File

@ -69,6 +69,10 @@ func (s *Server) UpdateMyUserProfile(ctx context.Context, request *auth.UpdateUs
return profileFromModel(profile), nil return profileFromModel(profile), nil
} }
func (s *Server) ChangeMyUserName(ctx context.Context, request *auth.ChangeUserNameRequest) (*empty.Empty, error) {
return &empty.Empty{}, s.repo.ChangeMyUsername(ctx, request.UserName)
}
func (s *Server) ChangeMyUserEmail(ctx context.Context, request *auth.UpdateUserEmailRequest) (*auth.UserEmail, error) { func (s *Server) ChangeMyUserEmail(ctx context.Context, request *auth.UpdateUserEmailRequest) (*auth.UserEmail, error) {
email, err := s.repo.ChangeMyEmail(ctx, updateEmailToModel(ctx, request)) email, err := s.repo.ChangeMyEmail(ctx, updateEmailToModel(ctx, request))
if err != nil { if err != nil {

View File

@ -5,8 +5,7 @@ import (
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/pkg/grpc/management" "github.com/caos/zitadel/pkg/grpc/management"
) )
@ -19,8 +18,8 @@ func (s *Server) GetUserByID(ctx context.Context, id *management.UserID) (*manag
return userViewFromModel(user), nil return userViewFromModel(user), nil
} }
func (s *Server) GetUserByEmailGlobal(ctx context.Context, email *management.Email) (*management.UserView, error) { func (s *Server) GetUserByLoginNameGlobal(ctx context.Context, loginName *management.LoginName) (*management.UserView, error) {
user, err := s.user.GetGlobalUserByEmail(ctx, email.Email) user, err := s.user.GetUserByLoginNameGlobal(ctx, loginName.LoginName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -29,8 +28,7 @@ func (s *Server) GetUserByEmailGlobal(ctx context.Context, email *management.Ema
func (s *Server) SearchUsers(ctx context.Context, in *management.UserSearchRequest) (*management.UserSearchResponse, error) { func (s *Server) SearchUsers(ctx context.Context, in *management.UserSearchRequest) (*management.UserSearchResponse, error) {
request := userSearchRequestsToModel(in) request := userSearchRequestsToModel(in)
orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID) request.AppendMyOrgQuery(authz.GetCtxData(ctx).OrgID)
request.AppendMyOrgQuery(orgID)
response, err := s.user.SearchUsers(ctx, request) response, err := s.user.SearchUsers(ctx, request)
if err != nil { if err != nil {
return nil, err return nil, err
@ -106,6 +104,10 @@ func (s *Server) GetUserProfile(ctx context.Context, in *management.UserID) (*ma
return profileViewFromModel(profile), nil return profileViewFromModel(profile), nil
} }
func (s *Server) ChangeUserUserName(ctx context.Context, request *management.UpdateUserUserNameRequest) (*empty.Empty, error) {
return &empty.Empty{}, s.user.ChangeUsername(ctx, request.Id, request.UserName)
}
func (s *Server) UpdateUserProfile(ctx context.Context, request *management.UpdateUserProfileRequest) (*management.UserProfile, error) { func (s *Server) UpdateUserProfile(ctx context.Context, request *management.UpdateUserProfileRequest) (*management.UserProfile, error) {
profile, err := s.user.ChangeProfile(ctx, updateProfileToModel(request)) profile, err := s.user.ChangeProfile(ctx, updateProfileToModel(request))
if err != nil { if err != nil {

View File

@ -59,6 +59,7 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re
middleware.NoCacheInterceptor(http_utils.CopyHeadersToContext(handlerFunc)) middleware.NoCacheInterceptor(http_utils.CopyHeadersToContext(handlerFunc))
} }
} }
config.OPConfig.CodeMethodS256 = true
provider, err := op.NewDefaultOP( provider, err := op.NewDefaultOP(
ctx, ctx,
config.OPConfig, config.OPConfig,

View File

@ -239,8 +239,11 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
if !user.IsEmailVerified { if !user.IsEmailVerified {
steps = append(steps, &model.VerifyEMailStep{}) steps = append(steps, &model.VerifyEMailStep{})
} }
if user.UsernameChangeRequired {
steps = append(steps, &model.ChangeUsernameStep{})
}
if user.PasswordChangeRequired || !user.IsEmailVerified { if user.PasswordChangeRequired || !user.IsEmailVerified || user.UsernameChangeRequired {
return steps, nil return steps, nil
} }

View File

@ -220,6 +220,14 @@ func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error {
return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID) return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID)
} }
func (repo *UserRepo) ChangeMyUsername(ctx context.Context, username string) error {
ctxData := authz.GetCtxData(ctx)
orgPolicy, err := repo.OrgEvents.GetOrgIAMPolicy(ctx, ctxData.OrgID)
if err != nil {
return err
}
return repo.UserEvents.ChangeUsername(ctx, ctxData.UserID, username, orgPolicy)
}
func (repo *UserRepo) ResendInitVerificationMail(ctx context.Context, userID string) error { func (repo *UserRepo) ResendInitVerificationMail(ctx context.Context, userID string) error {
_, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID) _, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID)
return err return err
@ -299,6 +307,15 @@ func (repo *UserRepo) MyUserChanges(ctx context.Context, lastSequence uint64, li
return changes, nil return changes, nil
} }
func (repo *UserRepo) ChangeUsername(ctx context.Context, userID, username string) error {
policyResourceOwner := authz.GetCtxData(ctx).OrgID
orgPolicy, err := repo.OrgEvents.GetOrgIAMPolicy(ctx, policyResourceOwner)
if err != nil {
return err
}
return repo.UserEvents.ChangeUsername(ctx, userID, username, orgPolicy)
}
func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error { func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error {
if obj.AggregateID != authz.GetCtxData(ctx).UserID { if obj.AggregateID != authz.GetCtxData(ctx).UserID {
return errors.ThrowPermissionDenied(nil, "EVENT-kFi9w", "object does not belong to user") return errors.ThrowPermissionDenied(nil, "EVENT-kFi9w", "object does not belong to user")

View File

@ -83,7 +83,8 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
return err return err
} }
err = user.AppendEvent(event) err = user.AppendEvent(event)
case es_model.DomainClaimed: case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID) user, err = u.view.UserByID(event.AggregateID)
if err != nil { if err != nil {
return err return err

View File

@ -65,7 +65,9 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.MfaOtpRemoved, es_model.MfaOtpRemoved,
es_model.UserProfileChanged, es_model.UserProfileChanged,
es_model.UserLocked, es_model.UserLocked,
es_model.UserDeactivated: es_model.UserDeactivated,
es_model.DomainClaimed,
es_model.UserUserNameChanged:
sessions, err := u.view.UserSessionsByUserID(event.AggregateID) sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
if err != nil { if err != nil {
return err return err

View File

@ -35,8 +35,8 @@ func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserV
return view.SearchUsers(v.Db, userTable, request) return view.SearchUsers(v.Db, userTable, request)
} }
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) { func (v *View) GetGlobalUserByLoginName(email string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email) return view.GetGlobalUserByLoginName(v.Db, userTable, email)
} }
func (v *View) IsUserUnique(userName, email string) (bool, error) { func (v *View) IsUserUnique(userName, email string) (bool, error) {

View File

@ -15,4 +15,5 @@ type Repository interface {
UserGrantRepository UserGrantRepository
PolicyRepository PolicyRepository
OrgRepository OrgRepository
IAMRepository
} }

View File

@ -21,9 +21,14 @@ type UserRepository interface {
VerifyEmail(ctx context.Context, userID, code string) error VerifyEmail(ctx context.Context, userID, code string) error
ResendEmailVerificationMail(ctx context.Context, userID string) error ResendEmailVerificationMail(ctx context.Context, userID string) error
VerifyInitCode(ctx context.Context, userID, code, password string) error
ResendInitVerificationMail(ctx context.Context, userID string) error
AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error)
VerifyMfaOTPSetup(ctx context.Context, userID, code string) error VerifyMfaOTPSetup(ctx context.Context, userID, code string) error
ChangeUsername(ctx context.Context, userID, username string) error
SignOut(ctx context.Context, agentID string) error SignOut(ctx context.Context, agentID string) error
UserByID(ctx context.Context, userID string) (*model.UserView, error) UserByID(ctx context.Context, userID string) (*model.UserView, error)
@ -56,5 +61,7 @@ type myUserRepo interface {
VerifyMyMfaOTPSetup(ctx context.Context, code string) error VerifyMyMfaOTPSetup(ctx context.Context, code string) error
RemoveMyMfaOTP(ctx context.Context) error RemoveMyMfaOTP(ctx context.Context) error
ChangeMyUsername(ctx context.Context, username string) error
MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) MyUserChanges(ctx context.Context, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error)
} }

View File

@ -18,6 +18,7 @@ const (
NextStepMfaPrompt NextStepMfaPrompt
NextStepMfaVerify NextStepMfaVerify
NextStepRedirectToCallback NextStepRedirectToCallback
NextStepChangeUsername
) )
type UserSessionState int32 type UserSessionState int32
@ -74,6 +75,12 @@ func (s *InitPasswordStep) Type() NextStepType {
return NextStepInitPassword return NextStepInitPassword
} }
type ChangeUsernameStep struct{}
func (s *ChangeUsernameStep) Type() NextStepType {
return NextStepChangeUsername
}
type VerifyEMailStep struct{} type VerifyEMailStep struct{}
func (s *VerifyEMailStep) Type() NextStepType { func (s *VerifyEMailStep) Type() NextStepType {

View File

@ -81,6 +81,7 @@ type Endpoints struct {
InitCode string InitCode string
PasswordReset string PasswordReset string
VerifyEmail string VerifyEmail string
DomainClaimed string
} }
type Providers struct { type Providers struct {
@ -94,4 +95,5 @@ type TemplateData struct {
PasswordReset templates.TemplateData PasswordReset templates.TemplateData
VerifyEmail templates.TemplateData VerifyEmail templates.TemplateData
VerifyPhone templates.TemplateData VerifyPhone templates.TemplateData
DomainClaimed templates.TemplateData
} }

View File

@ -132,8 +132,8 @@ func (repo *UserRepo) UserChanges(ctx context.Context, id string, lastSequence u
return changes, nil return changes, nil
} }
func (repo *UserRepo) GetGlobalUserByEmail(ctx context.Context, email string) (*usr_model.UserView, error) { func (repo *UserRepo) GetUserByLoginNameGlobal(ctx context.Context, loginName string) (*usr_model.UserView, error) {
user, err := repo.View.GetGlobalUserByEmail(email) user, err := repo.View.GetGlobalUserByLoginName(loginName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -179,6 +179,14 @@ func (repo *UserRepo) ChangeProfile(ctx context.Context, profile *usr_model.Prof
return repo.UserEvents.ChangeProfile(ctx, profile) return repo.UserEvents.ChangeProfile(ctx, profile)
} }
func (repo *UserRepo) ChangeUsername(ctx context.Context, userID, userName string) error {
orgPolicy, err := repo.OrgEvents.GetOrgIAMPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil {
return err
}
return repo.UserEvents.ChangeUsername(ctx, userID, userName, orgPolicy)
}
func (repo *UserRepo) EmailByID(ctx context.Context, userID string) (*usr_model.Email, error) { func (repo *UserRepo) EmailByID(ctx context.Context, userID string) (*usr_model.Email, error) {
user, err := repo.UserByID(ctx, userID) user, err := repo.UserByID(ctx, userID)
if err != nil { if err != nil {

View File

@ -80,7 +80,8 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
return err return err
} }
err = user.AppendEvent(event) err = user.AppendEvent(event)
case es_model.DomainClaimed: case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID) user, err = u.view.UserByID(event.AggregateID)
if err != nil { if err != nil {
return err return err

View File

@ -19,8 +19,8 @@ func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserV
return view.SearchUsers(v.Db, userTable, request) return view.SearchUsers(v.Db, userTable, request)
} }
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) { func (v *View) GetGlobalUserByLoginName(loginName string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email) return view.GetGlobalUserByLoginName(v.Db, userTable, loginName)
} }
func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) { func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) {

View File

@ -16,7 +16,7 @@ type UserRepository interface {
UnlockUser(ctx context.Context, id string) (*model.User, error) UnlockUser(ctx context.Context, id string) (*model.User, error)
SearchUsers(ctx context.Context, request *model.UserSearchRequest) (*model.UserSearchResponse, error) SearchUsers(ctx context.Context, request *model.UserSearchRequest) (*model.UserSearchResponse, error)
UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error) UserChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*model.UserChanges, error)
GetGlobalUserByEmail(ctx context.Context, email string) (*model.UserView, error) GetUserByLoginNameGlobal(ctx context.Context, email string) (*model.UserView, error)
IsUserUnique(ctx context.Context, userName, email string) (bool, error) IsUserUnique(ctx context.Context, userName, email string) (bool, error)
UserMfas(ctx context.Context, userID string) ([]*model.MultiFactor, error) UserMfas(ctx context.Context, userID string) ([]*model.MultiFactor, error)
@ -26,6 +26,8 @@ type UserRepository interface {
ProfileByID(ctx context.Context, userID string) (*model.Profile, error) ProfileByID(ctx context.Context, userID string) (*model.Profile, error)
ChangeProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error) ChangeProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error)
ChangeUsername(ctx context.Context, id, username string) error
EmailByID(ctx context.Context, userID string) (*model.Email, error) EmailByID(ctx context.Context, userID string) (*model.Email, error)
ChangeEmail(ctx context.Context, email *model.Email) (*model.Email, error) ChangeEmail(ctx context.Context, email *model.Email) (*model.Email, error)
CreateEmailVerificationCode(ctx context.Context, userID string) error CreateEmailVerificationCode(ctx context.Context, userID string) error

View File

@ -2,6 +2,7 @@ package handler
import ( import (
"context" "context"
"encoding/json"
"net/http" "net/http"
"github.com/caos/logging" "github.com/caos/logging"
@ -9,6 +10,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
sd "github.com/caos/zitadel/internal/config/systemdefaults" sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/spooler" "github.com/caos/zitadel/internal/eventstore/spooler"
@ -56,6 +58,8 @@ func (n *Notification) Reduce(event *models.Event) (err error) {
err = n.handlePhoneVerificationCode(event) err = n.handlePhoneVerificationCode(event)
case es_model.UserPasswordCodeAdded: case es_model.UserPasswordCodeAdded:
err = n.handlePasswordCode(event) err = n.handlePasswordCode(event)
case es_model.DomainClaimed:
err = n.handleDomainClaimed(event)
default: default:
return n.view.ProcessedNotificationSequence(event.Sequence) return n.view.ProcessedNotificationSequence(event.Sequence)
} }
@ -137,6 +141,27 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err
return n.userEvents.PhoneVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID) return n.userEvents.PhoneVerificationCodeSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID)
} }
func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
alreadyHandled, err := n.checkIfCodeAlreadyHandled(event.AggregateID, event.Sequence, es_model.DomainClaimed, es_model.DomainClaimedSent)
if err != nil || alreadyHandled {
return nil
}
data := make(map[string]string)
if err := json.Unmarshal(event.Data, &data); err != nil {
logging.Log("HANDLE-Gghq2").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "HANDLE-7hgj3", "could not unmarshal event")
}
user, err := n.view.NotifyUserByID(event.AggregateID)
if err != nil {
return err
}
err = types.SendDomainClaimed(n.statikDir, n.i18n, user, data["userName"], n.systemDefaults)
if err != nil {
return err
}
return n.userEvents.DomainClaimedSent(getSetNotifyContextData(event.ResourceOwner), event.AggregateID)
}
func (n *Notification) checkIfCodeAlreadyHandled(userID string, sequence uint64, addedType, sentType models.EventType) (bool, error) { func (n *Notification) checkIfCodeAlreadyHandled(userID string, sequence uint64, addedType, sentType models.EventType) (bool, error) {
events, err := n.getUserEvents(userID, sequence) events, err := n.getUserEvents(userID, sequence)
if err != nil { if err != nil {

View File

@ -69,6 +69,17 @@ func (u *NotifyUser) ProcessUser(event *models.Event) (err error) {
return err return err
} }
err = user.AppendEvent(event) err = user.AppendEvent(event)
case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.NotifyUserByID(event.AggregateID)
if err != nil {
return err
}
err = user.AppendEvent(event)
if err != nil {
return err
}
u.fillLoginNames(user)
case es_model.UserRemoved: case es_model.UserRemoved:
err = u.view.DeleteNotifyUser(event.AggregateID, event.Sequence) err = u.view.DeleteNotifyUser(event.AggregateID, event.Sequence)
default: default:

View File

@ -26,4 +26,10 @@ VerifyPhone:
Greeting: Hallo {{.FirstName}} {{.LastName}}, Greeting: Hallo {{.FirstName}} {{.LastName}},
Text: Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst {{.Code}} Text: Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst {{.Code}}
ButtonText: Telefon verifizieren ButtonText: Telefon verifizieren
DomainClaimed:
Title: Zitadel - Domain wurde beansprucht
PreHeader: Email / Username ändern
Subject: Domain wurde beansprucht
Greeting: Hallo {{.FirstName}} {{.LastName}},
Text: Die Domain {{.Domain}} wurde von einer Organisation beansprucht. Dein derzeitiger User {{.Username}} ist nicht Teil dieser Organisation. Daher musst du beim nächsten Login eine neue Email hinterlegen. Für diesen Login haben wir dir einen temporären Usernamen ({{.TempUsername}}) erstellt.
ButtonText: Login

View File

@ -26,4 +26,10 @@ VerifyPhone:
Greeting: Hello {{.FirstName}} {{.LastName}}, Greeting: Hello {{.FirstName}} {{.LastName}},
Text: A new phonenumber has been added. Please use the following code to verify it {{.Code}} Text: A new phonenumber has been added. Please use the following code to verify it {{.Code}}
ButtonText: Verify phone ButtonText: Verify phone
DomainClaimed:
Title: Zitadel - Domain has been claimed
PreHeader: Change email / username
Subject: Domain has been claimed
Greeting: Hello {{.FirstName}} {{.LastName}},
Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.Username}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login.
ButtonText: Login

View File

@ -0,0 +1,37 @@
package types
import (
"net/http"
"strings"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/templates"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
type DomainClaimedData struct {
templates.TemplateData
URL string
}
func SendDomainClaimed(dir http.FileSystem, i18n *i18n.Translator, user *view_model.NotifyUser, username string, systemDefaults systemdefaults.SystemDefaults) error {
url, err := templates.ParseTemplateText(systemDefaults.Notifications.Endpoints.DomainClaimed, &UrlData{UserID: user.ID})
if err != nil {
return err
}
var args = map[string]interface{}{
"FirstName": user.FirstName,
"LastName": user.LastName,
"Username": user.LastEmail,
"TempUsername": username,
"Domain": strings.Split(user.LastEmail, "@")[1],
}
systemDefaults.Notifications.TemplateData.DomainClaimed.Translate(i18n, args, user.PreferredLanguage)
data := &DomainClaimedData{TemplateData: systemDefaults.Notifications.TemplateData.DomainClaimed, URL: url}
template, err := templates.GetParsedTemplate(dir, data)
if err != nil {
return err
}
return generateEmail(user, systemDefaults.Notifications.TemplateData.DomainClaimed.Subject, template, systemDefaults.Notifications, true)
}

View File

@ -8,7 +8,7 @@ Errors:
OrgIamPolicyNil: Organisation Policy is empty OrgIamPolicyNil: Organisation Policy is empty
EmailAsUsernameNotAllowed: Email is not allowed as username EmailAsUsernameNotAllowed: Email is not allowed as username
Invalid: Userdata is invalid Invalid: Userdata is invalid
DomainNotAllowedAsUsername: Domain is already reserved DomainNotAllowedAsUsername: Domain is already reserved and cannot be used
AlreadyInactive: User already inactive AlreadyInactive: User already inactive
NotInactive: User is not inactive NotInactive: User is not inactive
ShouldBeActiveOrInitial: User is not active or inital ShouldBeActiveOrInitial: User is not active or inital

View File

@ -12,6 +12,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http/middleware" "github.com/caos/zitadel/internal/api/http/middleware"
auth_repository "github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing" "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/form" "github.com/caos/zitadel/internal/form"
@ -23,7 +24,7 @@ type Login struct {
router http.Handler router http.Handler
renderer *Renderer renderer *Renderer
parser *form.Parser parser *form.Parser
authRepo *eventsourcing.EsRepository authRepo auth_repository.Repository
zitadelURL string zitadelURL string
oidcAuthCallbackURL string oidcAuthCallbackURL string
} }

View File

@ -53,6 +53,8 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
tmplRegister: "register.html", tmplRegister: "register.html",
tmplLogoutDone: "logout_done.html", tmplLogoutDone: "logout_done.html",
tmplRegisterOrg: "register_org.html", tmplRegisterOrg: "register_org.html",
tmplChangeUsername: "change_username.html",
tmplChangeUsernameDone: "change_username_done.html",
} }
funcs := map[string]interface{}{ funcs := map[string]interface{}{
"resourceUrl": func(file string) string { "resourceUrl": func(file string) string {
@ -112,6 +114,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
"orgRegistrationUrl": func() string { "orgRegistrationUrl": func() string {
return path.Join(r.pathPrefix, EndpointRegisterOrg) return path.Join(r.pathPrefix, EndpointRegisterOrg)
}, },
"changeUsernameUrl": func() string {
return path.Join(r.pathPrefix, EndpointChangeUsername)
},
"selectedLanguage": func(l string) bool { "selectedLanguage": func(l string) bool {
return false return false
}, },
@ -179,6 +184,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
l.renderMfaPrompt(w, r, authReq, step, err) l.renderMfaPrompt(w, r, authReq, step, err)
case *model.InitUserStep: case *model.InitUserStep:
l.renderInitUser(w, r, authReq, "", "", step.PasswordSet, nil) l.renderInitUser(w, r, authReq, "", "", step.PasswordSet, nil)
case *model.ChangeUsernameStep:
l.renderChangeUsername(w, r, authReq, nil)
default: default:
l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible")) l.renderInternalError(w, r, authReq, caos_errs.ThrowInternal(nil, "APP-ds3QF", "step no possible"))
} }

View File

@ -13,6 +13,7 @@ const (
EndpointLogin = "/login" EndpointLogin = "/login"
EndpointLoginName = "/loginname" EndpointLoginName = "/loginname"
EndpointUserSelection = "/userselection" EndpointUserSelection = "/userselection"
EndpointChangeUsername = "/username/change"
EndpointPassword = "/password" EndpointPassword = "/password"
EndpointInitPassword = "/password/init" EndpointInitPassword = "/password/init"
EndpointChangePassword = "/password/change" EndpointChangePassword = "/password/change"
@ -40,6 +41,7 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
router.HandleFunc(EndpointLoginName, login.handleLoginName).Methods(http.MethodGet) router.HandleFunc(EndpointLoginName, login.handleLoginName).Methods(http.MethodGet)
router.HandleFunc(EndpointLoginName, login.handleLoginNameCheck).Methods(http.MethodPost) router.HandleFunc(EndpointLoginName, login.handleLoginNameCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost) router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost)
router.HandleFunc(EndpointChangeUsername, login.handleChangeUsername).Methods(http.MethodPost)
router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost) router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet) router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet)
router.HandleFunc(EndpointInitPassword, login.handleInitPasswordCheck).Methods(http.MethodPost) router.HandleFunc(EndpointInitPassword, login.handleInitPasswordCheck).Methods(http.MethodPost)

View File

@ -0,0 +1,46 @@
package handler
import (
"net/http"
"github.com/caos/zitadel/internal/auth_request/model"
)
const (
tmplChangeUsername = "changeusername"
tmplChangeUsernameDone = "changeusernamedone"
)
type changeUsernameData struct {
Username string `schema:"username"`
}
func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
var errType, errMessage string
if err != nil {
errMessage = l.getErrorMessage(r, err)
}
data := l.getUserData(r, authReq, "Change Username", errType, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsername], data, nil)
}
func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
data := new(changeUsernameData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return
}
err = l.authRepo.ChangeUsername(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Username)
if err != nil {
l.renderChangeUsername(w, r, authReq, err)
return
}
l.renderChangeUsernameDone(w, r, authReq)
}
func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
var errType, errMessage string
data := l.getUserData(r, authReq, "Username Change Done", errType, errMessage)
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangeUsernameDone], data, nil)
}

View File

@ -21,6 +21,15 @@ UserSelection:
SessionState0: aktiv SessionState0: aktiv
SessionState1: inaktiv SessionState1: inaktiv
UsernameChange:
Title: Usernamen ändern
Description: Wähle deinen neuen Benutzernamen
Username: Benutzernamen
UsernameChangeDone:
Title: Username geändert
Description: Der Username wurde erfolgreich geändert.
MfaVerify: MfaVerify:
Title: Multifaktor verifizieren Title: Multifaktor verifizieren
Description: Verifiziere deinen Multifaktor Description: Verifiziere deinen Multifaktor
@ -153,6 +162,7 @@ Errors:
NotMatchingUserID: User stimm nicht mit User in Auth Request überein NotMatchingUserID: User stimm nicht mit User in Auth Request überein
UserIDMissing: UserID ist leer UserIDMissing: UserID ist leer
Invalid: Userdaten sind ungültig Invalid: Userdaten sind ungültig
DomainNotAllowedAsUsername: Domäne ist bereits reserviert und kann nicht verwendet werden
Password: Password:
ConfirmationWrong: Passwort Bestätigung stimmt nicht überein ConfirmationWrong: Passwort Bestätigung stimmt nicht überein
Empty: Passwort ist leer Empty: Passwort ist leer

View File

@ -21,6 +21,15 @@ Password:
HasNumber: Number HasNumber: Number
HasSymbol: Symbol HasSymbol: Symbol
UsernameChange:
Title: Change Username
Description: Set your new username
Username: Username
UsernameChangeDone:
Title: Username changed
Description: Your username was changed successfully.
MfaVerify: MfaVerify:
Title: Verify Multificator Title: Verify Multificator
Description: Verify your multifactor Description: Verify your multifactor
@ -155,6 +164,7 @@ Errors:
NotMatchingUserID: User and user in authrequest don't match NotMatchingUserID: User and user in authrequest don't match
UserIDMissing: UserID is empty UserIDMissing: UserID is empty
Invalid: Invalid userdata Invalid: Invalid userdata
DomainNotAllowedAsUsername: Domain is already reserved and cannot be used
Password: Password:
ConfirmationWrong: Passwordconfirmation is wrong ConfirmationWrong: Passwordconfirmation is wrong
Empty: Password is empty Empty: Password is empty

View File

@ -2,6 +2,7 @@ function disableSubmit(checks, button) {
let form = document.getElementsByTagName('form')[0]; let form = document.getElementsByTagName('form')[0];
let inputs = form.getElementsByTagName('input'); let inputs = form.getElementsByTagName('input');
for (i = 0; i < inputs.length; i++) { for (i = 0; i < inputs.length; i++) {
button.disabled = true;
inputs[i].addEventListener('input', function () { inputs[i].addEventListener('input', function () {
if (checks != undefined) { if (checks != undefined) {
if (checks() === false) { if (checks() === false) {

View File

@ -41,7 +41,7 @@
{{ template "error-message" .}} {{ template "error-message" .}}
<div class="actions"> <div class="actions">
<button type="submit" id="change-password-button" name="resend" value="false" class="primary right" disabled>{{t "Actions.Next"}}</buttontype="submit"> <button type="submit" id="change-password-button" name="resend" value="false" class="primary right">{{t "Actions.Next"}}</button>
<a href="{{ loginUrl }}"> <a href="{{ loginUrl }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button> <button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
</a> </a>

View File

@ -0,0 +1,35 @@
{{template "main-top" .}}
{{ template "user-profile" . }}
<p>{{t "UsernameChange.Description"}}</p>
<form action="{{ changeUsernameUrl }}" method="POST">
{{ .CSRF }}
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="fields">
<div class="field">
<label class="label" for="username">{{t "UsernameChange.Username"}}</label>
<input class="input" type="text" id="username" name="username" autocomplete="username" autofocus required>
</div>
</div>
{{ template "error-message" .}}
<div class="actions">
<button type="submit" id="submit-button" value="false" class="primary right">{{t "Actions.Next"}}</button>
<a href="{{ loginUrl }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
</a>
</div>
</form>
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
{{template "main-bottom" .}}

View File

@ -0,0 +1,21 @@
{{template "main-top" .}}
{{ template "user-profile" . }}
<p>{{t "UsernameChangeDone.Description"}}</p>
<form action="{{ loginUrl }}" method="POST">
{{ .CSRF }}
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="actions">
<button class="primary right" type="submit">{{t "Actions.Next"}}</button>
</div>
</form>
{{template "main-bottom" .}}

View File

@ -47,8 +47,7 @@
id="init-button" id="init-button"
name="resend" name="resend"
value="false" value="false"
class="primary right" class="primary right">{{t "Actions.Next"}}</button>
{{ if not .PasswordSet }} disabled {{ end }}>{{t "Actions.Next"}}</button>
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend" }}</button> <button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend" }}</button>
<a href="{{ loginUrl }}"> <a href="{{ loginUrl }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button> <button class="secondary" type="button">{{t "Actions.Cancel"}}</button>

View File

@ -20,7 +20,7 @@
{{template "error-message" .}} {{template "error-message" .}}
<div class="actions"> <div class="actions">
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button> <button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<button class="secondary right" name="register" value="true" formnovalidate>{{t "Actions.Register"}}</button> <button class="secondary right" name="register" value="true" formnovalidate>{{t "Actions.Register"}}</button>
</div> </div>
</form> </form>

View File

@ -21,7 +21,7 @@
{{ template "error-message" .}} {{ template "error-message" .}}
<div class="actions"> <div class="actions">
<button type="submit" id="submit-button" name="resend" value="false" class="primary right" disabled>{{t "Actions.Next"}}</button> <button type="submit" id="submit-button" name="resend" value="false" class="primary right">{{t "Actions.Next"}}</button>
{{ if .UserID }} {{ if .UserID }}
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend"}}</button> <button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend"}}</button>
{{ end }} {{ end }}

View File

@ -34,7 +34,7 @@
{{end}} {{end}}
<div class="actions"> <div class="actions">
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button> <button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<a href="{{ mfaPromptChangeUrl .AuthReqID .MfaType }}"> <a href="{{ mfaPromptChangeUrl .AuthReqID .MfaType }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button> <button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a> </a>

View File

@ -21,7 +21,7 @@
{{ template "error-message" .}} {{ template "error-message" .}}
<div class="actions"> <div class="actions">
<button class="primary right" id="submit-button" type="submit" disabled>{{t "Actions.Next"}}</button> <button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<a href="{{ loginUrl }}"> <a href="{{ loginUrl }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button> <button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
</a> </a>

View File

@ -21,7 +21,7 @@
{{template "error-message" .}} {{template "error-message" .}}
<div class="actions"> <div class="actions">
<button id="submit-button" class="primary right" type="submit" disabled>{{t "Actions.Next"}}</button> <button id="submit-button" class="primary right" type="submit">{{t "Actions.Next"}}</button>
<a href="{{ loginNameChangeUrl .AuthReqID }}"> <a href="{{ loginNameChangeUrl .AuthReqID }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button> <button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a> </a>

View File

@ -61,7 +61,7 @@
{{template "error-message" .}} {{template "error-message" .}}
<div class="actions"> <div class="actions">
<button class="primary right" id="register-button" type="submit" disabled>{{t "Actions.Next"}}</button> <button class="primary right" id="register-button" type="submit">{{t "Actions.Next"}}</button>
<a href="{{ loginNameChangeUrl .AuthReqID }}"> <a href="{{ loginNameChangeUrl .AuthReqID }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button> <button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a> </a>

View File

@ -59,7 +59,7 @@
{{template "error-message" .}} {{template "error-message" .}}
<div class="actions"> <div class="actions">
<button class="primary right" id="register-button" type="submit" disabled>{{t "Actions.Save"}}</button> <button class="primary right" id="register-button" type="submit">{{t "Actions.Save"}}</button>
</div> </div>
</form> </form>

View File

@ -1,10 +1,12 @@
package model package model
import ( import (
"github.com/caos/zitadel/internal/eventstore/models"
"golang.org/x/text/language"
"time" "time"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/eventstore/models"
req_model "github.com/caos/zitadel/internal/auth_request/model" req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/model" "github.com/caos/zitadel/internal/model"
) )
@ -17,6 +19,7 @@ type UserView struct {
ResourceOwner string ResourceOwner string
PasswordSet bool PasswordSet bool
PasswordChangeRequired bool PasswordChangeRequired bool
UsernameChangeRequired bool
PasswordChanged time.Time PasswordChanged time.Time
LastLogin time.Time LastLogin time.Time
UserName string UserName string

View File

@ -670,11 +670,11 @@ func (es *UserEventstore) ChangeEmail(ctx context.Context, email *usr_model.Emai
repoNew := model.EmailFromModel(email) repoNew := model.EmailFromModel(email)
repoEmailCode := model.EmailCodeFromModel(emailCode) repoEmailCode := model.EmailCodeFromModel(emailCode)
updateAggregates, err := EmailChangeAggregate(ctx, es.AggregateCreator(), repoExisting, repoNew, repoEmailCode) updateAggregate, err := EmailChangeAggregate(ctx, es.AggregateCreator(), repoExisting, repoNew, repoEmailCode)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregates...) err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1112,6 +1112,48 @@ func (es *UserEventstore) PrepareDomainClaimed(ctx context.Context, userIDs []st
return aggregates, nil return aggregates, nil
} }
func (es *UserEventstore) DomainClaimedSent(ctx context.Context, userID string) error {
if userID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-0posw", "Errors.User.UserIDMissing")
}
user, err := es.UserByID(ctx, userID)
if err != nil {
return err
}
repoUser := model.UserFromModel(user)
agg := DomainClaimedSentAggregate(es.AggregateCreator(), repoUser)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, agg)
if err != nil {
return err
}
es.userCache.cacheUser(repoUser)
return nil
}
func (es *UserEventstore) ChangeUsername(ctx context.Context, userID, username string, orgIamPolicy *org_model.OrgIAMPolicy) error {
user, err := es.UserByID(ctx, userID)
if err != nil {
return err
}
oldUsername := user.UserName
user.UserName = username
if err := user.CheckOrgIAMPolicy(orgIamPolicy); err != nil {
return err
}
repoUser := model.UserFromModel(user)
aggregates, err := UsernameChangedAggregates(ctx, es.AggregateCreator(), repoUser, oldUsername, orgIamPolicy.UserLoginMustBeDomain)
if err != nil {
return err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoUser.AppendEvents, aggregates...)
if err != nil {
return err
}
es.userCache.cacheUser(repoUser)
return nil
}
func (es *UserEventstore) generateTemporaryLoginName() (string, error) { func (es *UserEventstore) generateTemporaryLoginName() (string, error) {
id, err := es.idGenerator.Next() id, err := es.idGenerator.Next()
if err != nil { if err != nil {

View File

@ -5,7 +5,6 @@ import "github.com/caos/zitadel/internal/eventstore/models"
const ( const (
UserAggregate models.AggregateType = "user" UserAggregate models.AggregateType = "user"
UserUserNameAggregate models.AggregateType = "user.username" UserUserNameAggregate models.AggregateType = "user.username"
UserEmailAggregate models.AggregateType = "user.email"
UserAdded models.EventType = "user.added" UserAdded models.EventType = "user.added"
UserRegistered models.EventType = "user.selfregistered" UserRegistered models.EventType = "user.selfregistered"
@ -16,8 +15,6 @@ const (
UserUserNameReserved models.EventType = "user.username.reserved" UserUserNameReserved models.EventType = "user.username.reserved"
UserUserNameReleased models.EventType = "user.username.released" UserUserNameReleased models.EventType = "user.username.released"
UserEmailReserved models.EventType = "user.email.reserved"
UserEmailReleased models.EventType = "user.email.released"
UserLocked models.EventType = "user.locked" UserLocked models.EventType = "user.locked"
UserUnlocked models.EventType = "user.unlocked" UserUnlocked models.EventType = "user.unlocked"
@ -44,8 +41,9 @@ const (
UserPhoneCodeAdded models.EventType = "user.phone.code.added" UserPhoneCodeAdded models.EventType = "user.phone.code.added"
UserPhoneCodeSent models.EventType = "user.phone.code.sent" UserPhoneCodeSent models.EventType = "user.phone.code.sent"
UserProfileChanged models.EventType = "user.profile.changed" UserProfileChanged models.EventType = "user.profile.changed"
UserAddressChanged models.EventType = "user.address.changed" UserAddressChanged models.EventType = "user.address.changed"
UserUserNameChanged models.EventType = "user.username.changed"
MfaOtpAdded models.EventType = "user.mfa.otp.added" MfaOtpAdded models.EventType = "user.mfa.otp.added"
MfaOtpVerified models.EventType = "user.mfa.otp.verified" MfaOtpVerified models.EventType = "user.mfa.otp.verified"
@ -56,5 +54,6 @@ const (
SignedOut models.EventType = "user.signed.out" SignedOut models.EventType = "user.signed.out"
DomainClaimed models.EventType = "user.domain.claimed" DomainClaimed models.EventType = "user.domain.claimed"
DomainClaimedSent models.EventType = "user.domain.claimed.sent"
) )

View File

@ -134,7 +134,8 @@ func (u *User) AppendEvent(event *es_models.Event) (err error) {
case UserAdded, case UserAdded,
UserRegistered, UserRegistered,
UserProfileChanged, UserProfileChanged,
DomainClaimed: DomainClaimed,
UserUserNameChanged:
u.setData(event) u.setData(event)
case UserDeactivated: case UserDeactivated:
u.appendDeactivatedEvent() u.appendDeactivatedEvent()

View File

@ -33,14 +33,6 @@ func UserUserNameUniqueQuery(userName string) *es_models.SearchQuery {
SetLimit(1) SetLimit(1)
} }
func UserEmailUniqueQuery(email string) *es_models.SearchQuery {
return es_models.NewSearchQuery().
AggregateTypeFilter(model.UserEmailAggregate).
AggregateIDFilter(email).
OrderDesc().
SetLimit(1)
}
func UserAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User) (*es_models.Aggregate, error) { func UserAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User) (*es_models.Aggregate, error) {
if user == nil { if user == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dis83", "Errors.Internal") return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dis83", "Errors.Internal")
@ -111,11 +103,7 @@ func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
if err != nil { if err != nil {
return nil, err return nil, err
} }
return []*es_models.Aggregate{ return append(uniqueAggregates, agg), nil
agg,
uniqueAggregates[0],
uniqueAggregates[1],
}, nil
} }
func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, initCode *model.InitUserCode, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) { func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, initCode *model.InitUserCode, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
@ -148,11 +136,7 @@ func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateC
if err != nil { if err != nil {
return nil, err return nil, err
} }
return []*es_models.Aggregate{ return append(uniqueAggregates, agg), nil
agg,
uniqueAggregates[0],
uniqueAggregates[1],
}, nil
} }
func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) { func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
@ -161,13 +145,8 @@ func getUniqueUserAggregates(ctx context.Context, aggCreator *es_models.Aggregat
return nil, err return nil, err
} }
emailAggregate, err := reservedUniqueEmailAggregate(ctx, aggCreator, resourceOwner, user.EmailAddress)
if err != nil {
return nil, err
}
return []*es_models.Aggregate{ return []*es_models.Aggregate{
userNameAggregate, userNameAggregate,
emailAggregate,
}, nil }, nil
} }
func reservedUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, userName string, userLoginMustBeDomain bool) (*es_models.Aggregate, error) { func reservedUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, userName string, userLoginMustBeDomain bool) (*es_models.Aggregate, error) {
@ -206,36 +185,18 @@ func releasedUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.
return aggregate.SetPrecondition(UserUserNameUniqueQuery(username), isEventValidation(aggregate, model.UserUserNameReleased)), nil return aggregate.SetPrecondition(UserUserNameUniqueQuery(username), isEventValidation(aggregate, model.UserUserNameReleased)), nil
} }
func reservedUniqueEmailAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, email string) (aggregate *es_models.Aggregate, err error) { func changeUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, oldUsername, username string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
aggregate, err = aggCreator.NewAggregate(ctx, email, model.UserEmailAggregate, model.UserVersion, 0) aggregates := make([]*es_models.Aggregate, 2)
if resourceOwner != "" { var err error
aggregate, err = aggCreator.NewAggregate(ctx, email, model.UserEmailAggregate, model.UserVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) aggregates[0], err = releasedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, oldUsername)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
aggregate, err = aggregate.AppendEvent(model.UserEmailReserved, nil) aggregates[1], err = reservedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, username, userLoginMustBeDomain)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return aggregates, nil
return aggregate.SetPrecondition(UserEmailUniqueQuery(email), isEventValidation(aggregate, model.UserEmailReserved)), nil
}
func releasedUniqueEmailAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, email string) (aggregate *es_models.Aggregate, err error) {
aggregate, err = aggCreator.NewAggregate(ctx, email, model.UserEmailAggregate, model.UserVersion, 0)
if resourceOwner != "" {
aggregate, err = aggCreator.NewAggregate(ctx, email, model.UserEmailAggregate, model.UserVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
}
if err != nil {
return nil, err
}
aggregate, err = aggregate.AppendEvent(model.UserEmailReleased, nil)
if err != nil {
return nil, err
}
return aggregate.SetPrecondition(UserEmailUniqueQuery(email), isEventValidation(aggregate, model.UserEmailReleased)), nil
} }
func UserDeactivateAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { func UserDeactivateAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
@ -401,7 +362,7 @@ func ProfileChangeAggregate(aggCreator *es_models.AggregateCreator, existing *mo
} }
} }
func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.User, email *model.Email, code *model.EmailCode) ([]*es_models.Aggregate, error) { func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.User, email *model.Email, code *model.EmailCode) (*es_models.Aggregate, error) {
if email == nil { if email == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dki8s", "Errors.Internal") return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dki8s", "Errors.Internal")
} }
@ -412,17 +373,6 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr
if len(changes) == 0 { if len(changes) == 0 {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-s90pw", "Errors.NoChangesFound") return nil, errors.ThrowPreconditionFailed(nil, "EVENT-s90pw", "Errors.NoChangesFound")
} }
aggregates := make([]*es_models.Aggregate, 0, 4)
reserveEmailAggregate, err := reservedUniqueEmailAggregate(ctx, aggCreator, "", email.EmailAddress)
if err != nil {
return nil, err
}
aggregates = append(aggregates, reserveEmailAggregate)
releaseEmailAggregate, err := releasedUniqueEmailAggregate(ctx, aggCreator, "", existing.EmailAddress)
if err != nil {
return nil, err
}
aggregates = append(aggregates, releaseEmailAggregate)
agg, err := UserAggregate(ctx, aggCreator, existing) agg, err := UserAggregate(ctx, aggCreator, existing)
if err != nil { if err != nil {
return nil, err return nil, err
@ -446,7 +396,7 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr
return nil, err return nil, err
} }
} }
return append(aggregates, agg), nil return agg, nil
} }
func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc {
@ -673,7 +623,10 @@ func SignOutAggregates(aggCreator *es_models.AggregateCreator, existingUsers []*
} }
func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existingUser *model.User, tempName string) ([]*es_models.Aggregate, error) { func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existingUser *model.User, tempName string) ([]*es_models.Aggregate, error) {
aggregates := make([]*es_models.Aggregate, 3) aggregates, err := changeUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, existingUser.UserName, tempName, false)
if err != nil {
return nil, err
}
userAggregate, err := UserAggregateOverwriteContext(ctx, aggCreator, existingUser, existingUser.ResourceOwner, existingUser.AggregateID) userAggregate, err := UserAggregateOverwriteContext(ctx, aggCreator, existingUser, existingUser.ResourceOwner, existingUser.AggregateID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -682,18 +635,41 @@ func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.Aggregate
if err != nil { if err != nil {
return nil, err return nil, err
} }
aggregates[0] = userAggregate return append(aggregates, userAggregate), nil
releasedUniqueAggregate, err := releasedUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, existingUser.UserName) }
func DomainClaimedSentAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
agg, err := UserAggregate(ctx, aggCreator, user)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.DomainClaimedSent, nil)
}
}
func UsernameChangedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, oldUsername string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
aggregates, err := changeUniqueUserNameAggregate(ctx, aggCreator, user.ResourceOwner, oldUsername, user.UserName, userLoginMustBeDomain)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aggregates[1] = releasedUniqueAggregate userAggregate, err := UserAggregate(ctx, aggCreator, user)
reservedUniqueAggregate, err := reservedUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, tempName, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aggregates[2] = reservedUniqueAggregate userAggregate, err = userAggregate.AppendEvent(model.UserUserNameChanged, map[string]interface{}{"userName": user.UserName})
return aggregates, nil if err != nil {
return nil, err
}
if !userLoginMustBeDomain {
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter(org_es_model.OrgAggregate).
AggregateIDsFilter()
validation := addUserNameValidation(user.UserName)
userAggregate.SetPrecondition(validationQuery, validation)
}
return append(aggregates, userAggregate), nil
} }
func isEventValidation(aggregate *es_models.Aggregate, eventType es_models.EventType) func(...*es_models.Event) error { func isEventValidation(aggregate *es_models.Aggregate, eventType es_models.EventType) func(...*es_models.Event) error {

View File

@ -136,7 +136,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 1, eventLen: 1,
eventTypes: []models.EventType{model.UserAdded}, eventTypes: []models.EventType{model.UserAdded},
checkData: []bool{true}, checkData: []bool{true},
aggregatesLen: 3, aggregatesLen: 2,
}, },
}, },
{ {
@ -166,7 +166,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2, eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.InitializedUserCodeAdded}, eventTypes: []models.EventType{model.UserAdded, model.InitializedUserCodeAdded},
checkData: []bool{true, true}, checkData: []bool{true, true},
aggregatesLen: 3, aggregatesLen: 2,
}, },
}, },
{ {
@ -184,7 +184,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2, eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserPhoneCodeAdded}, eventTypes: []models.EventType{model.UserAdded, model.UserPhoneCodeAdded},
checkData: []bool{true, true}, checkData: []bool{true, true},
aggregatesLen: 3, aggregatesLen: 2,
}, },
}, },
{ {
@ -201,7 +201,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2, eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserEmailVerified}, eventTypes: []models.EventType{model.UserAdded, model.UserEmailVerified},
checkData: []bool{true, false}, checkData: []bool{true, false},
aggregatesLen: 3, aggregatesLen: 2,
}, },
}, },
{ {
@ -219,7 +219,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2, eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserPhoneVerified}, eventTypes: []models.EventType{model.UserAdded, model.UserPhoneVerified},
checkData: []bool{true, false}, checkData: []bool{true, false},
aggregatesLen: 3, aggregatesLen: 2,
}, },
}, },
} }
@ -231,17 +231,17 @@ func TestUserCreateAggregate(t *testing.T) {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.aggregatesLen, len(aggregates)) t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.aggregatesLen, len(aggregates))
} }
if !tt.res.wantErr && len(aggregates[0].Events) != tt.res.eventLen { if !tt.res.wantErr && len(aggregates[1].Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events)) t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events))
} }
for i := 0; i < tt.res.eventLen; i++ { for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && aggregates[0].Events[i].Type != tt.res.eventTypes[i] { if !tt.res.wantErr && aggregates[1].Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[0].Events[i].Type.String()) t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[1].Events[i].Type.String())
} }
if !tt.res.wantErr && tt.res.checkData[i] && aggregates[0].Events[i].Data == nil { if !tt.res.wantErr && tt.res.checkData[i] && aggregates[1].Events[i].Data == nil {
t.Errorf("should have data in event") t.Errorf("should have data in event")
} }
if !tt.res.wantErr && !tt.res.checkData[i] && aggregates[0].Events[i].Data != nil { if !tt.res.wantErr && !tt.res.checkData[i] && aggregates[1].Events[i].Data != nil {
t.Errorf("should not have data in event") t.Errorf("should not have data in event")
} }
} }
@ -352,14 +352,14 @@ func TestUserRegisterAggregate(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.initCode, false) aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.initCode, false)
if tt.res.errFunc == nil && len(aggregates[0].Events) != tt.res.eventLen { if tt.res.errFunc == nil && len(aggregates[1].Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events)) t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events))
} }
for i := 0; i < tt.res.eventLen; i++ { for i := 0; i < tt.res.eventLen; i++ {
if tt.res.errFunc == nil && aggregates[0].Events[i].Type != tt.res.eventTypes[i] { if tt.res.errFunc == nil && aggregates[1].Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[0].Events[i].Type.String()) t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[1].Events[i].Type.String())
} }
if tt.res.errFunc == nil && aggregates[0].Events[i].Data == nil { if tt.res.errFunc == nil && aggregates[1].Events[i].Data == nil {
t.Errorf("should have data in event") t.Errorf("should have data in event")
} }
} }
@ -1226,16 +1226,16 @@ func TestChangeEmailAggregate(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
aggregates, err := EmailChangeAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.email, tt.args.code) aggregate, err := EmailChangeAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.email, tt.args.code)
if tt.res.errFunc == nil && len(aggregates[2].Events) != tt.res.eventLen { if tt.res.errFunc == nil && len(aggregate.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events)) t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregate.Events))
} }
for i := 0; i < tt.res.eventLen; i++ { for i := 0; i < tt.res.eventLen; i++ {
if tt.res.errFunc == nil && aggregates[2].Events[i].Type != tt.res.eventTypes[i] { if tt.res.errFunc == nil && aggregate.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[1].Events[i].Type.String()) t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregate.Events[i].Type.String())
} }
if tt.res.errFunc == nil && aggregates[2].Events[i].Data == nil { if tt.res.errFunc == nil && aggregate.Events[i].Data == nil {
t.Errorf("should have data in event") t.Errorf("should have data in event")
} }
} }

View File

@ -36,6 +36,7 @@ type UserView struct {
State int32 `json:"-" gorm:"column:user_state"` State int32 `json:"-" gorm:"column:user_state"`
PasswordSet bool `json:"-" gorm:"column:password_set"` PasswordSet bool `json:"-" gorm:"column:password_set"`
PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"` PasswordChangeRequired bool `json:"-" gorm:"column:password_change_required"`
UsernameChangeRequired bool `json:"-" gorm:"column:username_change_required"`
PasswordChanged time.Time `json:"-" gorm:"column:password_change"` PasswordChanged time.Time `json:"-" gorm:"column:password_change"`
LastLogin time.Time `json:"-" gorm:"column:last_login"` LastLogin time.Time `json:"-" gorm:"column:last_login"`
UserName string `json:"userName" gorm:"column:user_name"` UserName string `json:"userName" gorm:"column:user_name"`
@ -72,6 +73,7 @@ func UserFromModel(user *model.UserView) *UserView {
State: int32(user.State), State: int32(user.State),
PasswordSet: user.PasswordSet, PasswordSet: user.PasswordSet,
PasswordChangeRequired: user.PasswordChangeRequired, PasswordChangeRequired: user.PasswordChangeRequired,
UsernameChangeRequired: user.UsernameChangeRequired,
PasswordChanged: user.PasswordChanged, PasswordChanged: user.PasswordChanged,
LastLogin: user.LastLogin, LastLogin: user.LastLogin,
UserName: user.UserName, UserName: user.UserName,
@ -109,6 +111,7 @@ func UserToModel(user *UserView) *model.UserView {
State: model.UserState(user.State), State: model.UserState(user.State),
PasswordSet: user.PasswordSet, PasswordSet: user.PasswordSet,
PasswordChangeRequired: user.PasswordChangeRequired, PasswordChangeRequired: user.PasswordChangeRequired,
UsernameChangeRequired: user.UsernameChangeRequired,
PasswordChanged: user.PasswordChanged, PasswordChanged: user.PasswordChanged,
LastLogin: user.LastLogin, LastLogin: user.LastLogin,
PreferredLoginName: user.PreferredLoginName, PreferredLoginName: user.PreferredLoginName,
@ -181,8 +184,13 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) {
case es_model.UserPasswordChanged: case es_model.UserPasswordChanged:
err = u.setPasswordData(event) err = u.setPasswordData(event)
case es_model.UserProfileChanged, case es_model.UserProfileChanged,
es_model.UserAddressChanged, es_model.UserAddressChanged:
es_model.DomainClaimed: err = u.setData(event)
case es_model.DomainClaimed:
u.UsernameChangeRequired = true
err = u.setData(event)
case es_model.UserUserNameChanged:
u.UsernameChangeRequired = false
err = u.setData(event) err = u.setData(event)
case es_model.UserEmailChanged: case es_model.UserEmailChanged:
u.IsEmailVerified = false u.IsEmailVerified = false

View File

@ -94,9 +94,9 @@ func SearchUsers(db *gorm.DB, table string, req *usr_model.UserSearchRequest) ([
return users, count, nil return users, count, nil
} }
func GetGlobalUserByEmail(db *gorm.DB, table, email string) (*model.UserView, error) { func GetGlobalUserByLoginName(db *gorm.DB, table, loginName string) (*model.UserView, error) {
user := new(model.UserView) user := new(model.UserView)
query := repository.PrepareGetByKey(table, model.UserSearchKey(usr_model.UserSearchKeyEmail), email) query := repository.PrepareGetByQuery(table, &model.UserSearchQuery{Key: usr_model.UserSearchKeyLoginNames, Value: loginName, Method: global_model.SearchMethodListContains})
err := query(db, user) err := query(db, user)
if caos_errs.IsNotFound(err) { if caos_errs.IsNotFound(err) {
return nil, caos_errs.ThrowNotFound(nil, "VIEW-8uWer", "Errors.User.NotFound") return nil, caos_errs.ThrowNotFound(nil, "VIEW-8uWer", "Errors.User.NotFound")

View File

@ -0,0 +1,7 @@
BEGIN;
ALTER TABLE management.users ADD COLUMN username_change_required BOOLEAN;
ALTER TABLE auth.users ADD COLUMN username_change_required BOOLEAN;
ALTER TABLE adminapi.users ADD COLUMN username_change_required BOOLEAN;
COMMIT;

View File

@ -34,6 +34,11 @@ var AuthService_AuthMethods = authz.MethodMapping{
CheckParam: "", CheckParam: "",
}, },
"/caos.zitadel.auth.api.v1.AuthService/ChangeMyUserName": authz.Option{
Permission: "authenticated",
CheckParam: "",
},
"/caos.zitadel.auth.api.v1.AuthService/GetMyUserEmail": authz.Option{ "/caos.zitadel.auth.api.v1.AuthService/GetMyUserEmail": authz.Option{
Permission: "authenticated", Permission: "authenticated",
CheckParam: "", CheckParam: "",

View File

@ -1006,6 +1006,45 @@ func (m *UpdateUserProfileRequest) GetGender() Gender {
return Gender_GENDER_UNSPECIFIED return Gender_GENDER_UNSPECIFIED
} }
type ChangeUserNameRequest struct {
UserName string `protobuf:"bytes,1,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ChangeUserNameRequest) Reset() { *m = ChangeUserNameRequest{} }
func (m *ChangeUserNameRequest) String() string { return proto.CompactTextString(m) }
func (*ChangeUserNameRequest) ProtoMessage() {}
func (*ChangeUserNameRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{6}
}
func (m *ChangeUserNameRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChangeUserNameRequest.Unmarshal(m, b)
}
func (m *ChangeUserNameRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ChangeUserNameRequest.Marshal(b, m, deterministic)
}
func (m *ChangeUserNameRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ChangeUserNameRequest.Merge(m, src)
}
func (m *ChangeUserNameRequest) XXX_Size() int {
return xxx_messageInfo_ChangeUserNameRequest.Size(m)
}
func (m *ChangeUserNameRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ChangeUserNameRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ChangeUserNameRequest proto.InternalMessageInfo
func (m *ChangeUserNameRequest) GetUserName() string {
if m != nil {
return m.UserName
}
return ""
}
type UserEmail struct { type UserEmail struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"`
@ -1022,7 +1061,7 @@ func (m *UserEmail) Reset() { *m = UserEmail{} }
func (m *UserEmail) String() string { return proto.CompactTextString(m) } func (m *UserEmail) String() string { return proto.CompactTextString(m) }
func (*UserEmail) ProtoMessage() {} func (*UserEmail) ProtoMessage() {}
func (*UserEmail) Descriptor() ([]byte, []int) { func (*UserEmail) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{6} return fileDescriptor_8bbd6f3875b0e874, []int{7}
} }
func (m *UserEmail) XXX_Unmarshal(b []byte) error { func (m *UserEmail) XXX_Unmarshal(b []byte) error {
@ -1101,7 +1140,7 @@ func (m *UserEmailView) Reset() { *m = UserEmailView{} }
func (m *UserEmailView) String() string { return proto.CompactTextString(m) } func (m *UserEmailView) String() string { return proto.CompactTextString(m) }
func (*UserEmailView) ProtoMessage() {} func (*UserEmailView) ProtoMessage() {}
func (*UserEmailView) Descriptor() ([]byte, []int) { func (*UserEmailView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{7} return fileDescriptor_8bbd6f3875b0e874, []int{8}
} }
func (m *UserEmailView) XXX_Unmarshal(b []byte) error { func (m *UserEmailView) XXX_Unmarshal(b []byte) error {
@ -1175,7 +1214,7 @@ func (m *VerifyMyUserEmailRequest) Reset() { *m = VerifyMyUserEmailReque
func (m *VerifyMyUserEmailRequest) String() string { return proto.CompactTextString(m) } func (m *VerifyMyUserEmailRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyMyUserEmailRequest) ProtoMessage() {} func (*VerifyMyUserEmailRequest) ProtoMessage() {}
func (*VerifyMyUserEmailRequest) Descriptor() ([]byte, []int) { func (*VerifyMyUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{8} return fileDescriptor_8bbd6f3875b0e874, []int{9}
} }
func (m *VerifyMyUserEmailRequest) XXX_Unmarshal(b []byte) error { func (m *VerifyMyUserEmailRequest) XXX_Unmarshal(b []byte) error {
@ -1215,7 +1254,7 @@ func (m *VerifyUserEmailRequest) Reset() { *m = VerifyUserEmailRequest{}
func (m *VerifyUserEmailRequest) String() string { return proto.CompactTextString(m) } func (m *VerifyUserEmailRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyUserEmailRequest) ProtoMessage() {} func (*VerifyUserEmailRequest) ProtoMessage() {}
func (*VerifyUserEmailRequest) Descriptor() ([]byte, []int) { func (*VerifyUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{9} return fileDescriptor_8bbd6f3875b0e874, []int{10}
} }
func (m *VerifyUserEmailRequest) XXX_Unmarshal(b []byte) error { func (m *VerifyUserEmailRequest) XXX_Unmarshal(b []byte) error {
@ -1261,7 +1300,7 @@ func (m *UpdateUserEmailRequest) Reset() { *m = UpdateUserEmailRequest{}
func (m *UpdateUserEmailRequest) String() string { return proto.CompactTextString(m) } func (m *UpdateUserEmailRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateUserEmailRequest) ProtoMessage() {} func (*UpdateUserEmailRequest) ProtoMessage() {}
func (*UpdateUserEmailRequest) Descriptor() ([]byte, []int) { func (*UpdateUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{10} return fileDescriptor_8bbd6f3875b0e874, []int{11}
} }
func (m *UpdateUserEmailRequest) XXX_Unmarshal(b []byte) error { func (m *UpdateUserEmailRequest) XXX_Unmarshal(b []byte) error {
@ -1305,7 +1344,7 @@ func (m *UserPhone) Reset() { *m = UserPhone{} }
func (m *UserPhone) String() string { return proto.CompactTextString(m) } func (m *UserPhone) String() string { return proto.CompactTextString(m) }
func (*UserPhone) ProtoMessage() {} func (*UserPhone) ProtoMessage() {}
func (*UserPhone) Descriptor() ([]byte, []int) { func (*UserPhone) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{11} return fileDescriptor_8bbd6f3875b0e874, []int{12}
} }
func (m *UserPhone) XXX_Unmarshal(b []byte) error { func (m *UserPhone) XXX_Unmarshal(b []byte) error {
@ -1384,7 +1423,7 @@ func (m *UserPhoneView) Reset() { *m = UserPhoneView{} }
func (m *UserPhoneView) String() string { return proto.CompactTextString(m) } func (m *UserPhoneView) String() string { return proto.CompactTextString(m) }
func (*UserPhoneView) ProtoMessage() {} func (*UserPhoneView) ProtoMessage() {}
func (*UserPhoneView) Descriptor() ([]byte, []int) { func (*UserPhoneView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{12} return fileDescriptor_8bbd6f3875b0e874, []int{13}
} }
func (m *UserPhoneView) XXX_Unmarshal(b []byte) error { func (m *UserPhoneView) XXX_Unmarshal(b []byte) error {
@ -1458,7 +1497,7 @@ func (m *UpdateUserPhoneRequest) Reset() { *m = UpdateUserPhoneRequest{}
func (m *UpdateUserPhoneRequest) String() string { return proto.CompactTextString(m) } func (m *UpdateUserPhoneRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateUserPhoneRequest) ProtoMessage() {} func (*UpdateUserPhoneRequest) ProtoMessage() {}
func (*UpdateUserPhoneRequest) Descriptor() ([]byte, []int) { func (*UpdateUserPhoneRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{13} return fileDescriptor_8bbd6f3875b0e874, []int{14}
} }
func (m *UpdateUserPhoneRequest) XXX_Unmarshal(b []byte) error { func (m *UpdateUserPhoneRequest) XXX_Unmarshal(b []byte) error {
@ -1497,7 +1536,7 @@ func (m *VerifyUserPhoneRequest) Reset() { *m = VerifyUserPhoneRequest{}
func (m *VerifyUserPhoneRequest) String() string { return proto.CompactTextString(m) } func (m *VerifyUserPhoneRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyUserPhoneRequest) ProtoMessage() {} func (*VerifyUserPhoneRequest) ProtoMessage() {}
func (*VerifyUserPhoneRequest) Descriptor() ([]byte, []int) { func (*VerifyUserPhoneRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{14} return fileDescriptor_8bbd6f3875b0e874, []int{15}
} }
func (m *VerifyUserPhoneRequest) XXX_Unmarshal(b []byte) error { func (m *VerifyUserPhoneRequest) XXX_Unmarshal(b []byte) error {
@ -1544,7 +1583,7 @@ func (m *UserAddress) Reset() { *m = UserAddress{} }
func (m *UserAddress) String() string { return proto.CompactTextString(m) } func (m *UserAddress) String() string { return proto.CompactTextString(m) }
func (*UserAddress) ProtoMessage() {} func (*UserAddress) ProtoMessage() {}
func (*UserAddress) Descriptor() ([]byte, []int) { func (*UserAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{15} return fileDescriptor_8bbd6f3875b0e874, []int{16}
} }
func (m *UserAddress) XXX_Unmarshal(b []byte) error { func (m *UserAddress) XXX_Unmarshal(b []byte) error {
@ -1647,7 +1686,7 @@ func (m *UserAddressView) Reset() { *m = UserAddressView{} }
func (m *UserAddressView) String() string { return proto.CompactTextString(m) } func (m *UserAddressView) String() string { return proto.CompactTextString(m) }
func (*UserAddressView) ProtoMessage() {} func (*UserAddressView) ProtoMessage() {}
func (*UserAddressView) Descriptor() ([]byte, []int) { func (*UserAddressView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{16} return fileDescriptor_8bbd6f3875b0e874, []int{17}
} }
func (m *UserAddressView) XXX_Unmarshal(b []byte) error { func (m *UserAddressView) XXX_Unmarshal(b []byte) error {
@ -1746,7 +1785,7 @@ func (m *UpdateUserAddressRequest) Reset() { *m = UpdateUserAddressReque
func (m *UpdateUserAddressRequest) String() string { return proto.CompactTextString(m) } func (m *UpdateUserAddressRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateUserAddressRequest) ProtoMessage() {} func (*UpdateUserAddressRequest) ProtoMessage() {}
func (*UpdateUserAddressRequest) Descriptor() ([]byte, []int) { func (*UpdateUserAddressRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{17} return fileDescriptor_8bbd6f3875b0e874, []int{18}
} }
func (m *UpdateUserAddressRequest) XXX_Unmarshal(b []byte) error { func (m *UpdateUserAddressRequest) XXX_Unmarshal(b []byte) error {
@ -1813,7 +1852,7 @@ func (m *PasswordID) Reset() { *m = PasswordID{} }
func (m *PasswordID) String() string { return proto.CompactTextString(m) } func (m *PasswordID) String() string { return proto.CompactTextString(m) }
func (*PasswordID) ProtoMessage() {} func (*PasswordID) ProtoMessage() {}
func (*PasswordID) Descriptor() ([]byte, []int) { func (*PasswordID) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{18} return fileDescriptor_8bbd6f3875b0e874, []int{19}
} }
func (m *PasswordID) XXX_Unmarshal(b []byte) error { func (m *PasswordID) XXX_Unmarshal(b []byte) error {
@ -1852,7 +1891,7 @@ func (m *PasswordRequest) Reset() { *m = PasswordRequest{} }
func (m *PasswordRequest) String() string { return proto.CompactTextString(m) } func (m *PasswordRequest) String() string { return proto.CompactTextString(m) }
func (*PasswordRequest) ProtoMessage() {} func (*PasswordRequest) ProtoMessage() {}
func (*PasswordRequest) Descriptor() ([]byte, []int) { func (*PasswordRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{19} return fileDescriptor_8bbd6f3875b0e874, []int{20}
} }
func (m *PasswordRequest) XXX_Unmarshal(b []byte) error { func (m *PasswordRequest) XXX_Unmarshal(b []byte) error {
@ -1892,7 +1931,7 @@ func (m *PasswordChange) Reset() { *m = PasswordChange{} }
func (m *PasswordChange) String() string { return proto.CompactTextString(m) } func (m *PasswordChange) String() string { return proto.CompactTextString(m) }
func (*PasswordChange) ProtoMessage() {} func (*PasswordChange) ProtoMessage() {}
func (*PasswordChange) Descriptor() ([]byte, []int) { func (*PasswordChange) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{20} return fileDescriptor_8bbd6f3875b0e874, []int{21}
} }
func (m *PasswordChange) XXX_Unmarshal(b []byte) error { func (m *PasswordChange) XXX_Unmarshal(b []byte) error {
@ -1938,7 +1977,7 @@ func (m *VerifyMfaOtp) Reset() { *m = VerifyMfaOtp{} }
func (m *VerifyMfaOtp) String() string { return proto.CompactTextString(m) } func (m *VerifyMfaOtp) String() string { return proto.CompactTextString(m) }
func (*VerifyMfaOtp) ProtoMessage() {} func (*VerifyMfaOtp) ProtoMessage() {}
func (*VerifyMfaOtp) Descriptor() ([]byte, []int) { func (*VerifyMfaOtp) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{21} return fileDescriptor_8bbd6f3875b0e874, []int{22}
} }
func (m *VerifyMfaOtp) XXX_Unmarshal(b []byte) error { func (m *VerifyMfaOtp) XXX_Unmarshal(b []byte) error {
@ -1977,7 +2016,7 @@ func (m *MultiFactors) Reset() { *m = MultiFactors{} }
func (m *MultiFactors) String() string { return proto.CompactTextString(m) } func (m *MultiFactors) String() string { return proto.CompactTextString(m) }
func (*MultiFactors) ProtoMessage() {} func (*MultiFactors) ProtoMessage() {}
func (*MultiFactors) Descriptor() ([]byte, []int) { func (*MultiFactors) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{22} return fileDescriptor_8bbd6f3875b0e874, []int{23}
} }
func (m *MultiFactors) XXX_Unmarshal(b []byte) error { func (m *MultiFactors) XXX_Unmarshal(b []byte) error {
@ -2017,7 +2056,7 @@ func (m *MultiFactor) Reset() { *m = MultiFactor{} }
func (m *MultiFactor) String() string { return proto.CompactTextString(m) } func (m *MultiFactor) String() string { return proto.CompactTextString(m) }
func (*MultiFactor) ProtoMessage() {} func (*MultiFactor) ProtoMessage() {}
func (*MultiFactor) Descriptor() ([]byte, []int) { func (*MultiFactor) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{23} return fileDescriptor_8bbd6f3875b0e874, []int{24}
} }
func (m *MultiFactor) XXX_Unmarshal(b []byte) error { func (m *MultiFactor) XXX_Unmarshal(b []byte) error {
@ -2066,7 +2105,7 @@ func (m *MfaOtpResponse) Reset() { *m = MfaOtpResponse{} }
func (m *MfaOtpResponse) String() string { return proto.CompactTextString(m) } func (m *MfaOtpResponse) String() string { return proto.CompactTextString(m) }
func (*MfaOtpResponse) ProtoMessage() {} func (*MfaOtpResponse) ProtoMessage() {}
func (*MfaOtpResponse) Descriptor() ([]byte, []int) { func (*MfaOtpResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{24} return fileDescriptor_8bbd6f3875b0e874, []int{25}
} }
func (m *MfaOtpResponse) XXX_Unmarshal(b []byte) error { func (m *MfaOtpResponse) XXX_Unmarshal(b []byte) error {
@ -2127,7 +2166,7 @@ func (m *OIDCClientAuth) Reset() { *m = OIDCClientAuth{} }
func (m *OIDCClientAuth) String() string { return proto.CompactTextString(m) } func (m *OIDCClientAuth) String() string { return proto.CompactTextString(m) }
func (*OIDCClientAuth) ProtoMessage() {} func (*OIDCClientAuth) ProtoMessage() {}
func (*OIDCClientAuth) Descriptor() ([]byte, []int) { func (*OIDCClientAuth) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{25} return fileDescriptor_8bbd6f3875b0e874, []int{26}
} }
func (m *OIDCClientAuth) XXX_Unmarshal(b []byte) error { func (m *OIDCClientAuth) XXX_Unmarshal(b []byte) error {
@ -2177,7 +2216,7 @@ func (m *UserGrantSearchRequest) Reset() { *m = UserGrantSearchRequest{}
func (m *UserGrantSearchRequest) String() string { return proto.CompactTextString(m) } func (m *UserGrantSearchRequest) String() string { return proto.CompactTextString(m) }
func (*UserGrantSearchRequest) ProtoMessage() {} func (*UserGrantSearchRequest) ProtoMessage() {}
func (*UserGrantSearchRequest) Descriptor() ([]byte, []int) { func (*UserGrantSearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{26} return fileDescriptor_8bbd6f3875b0e874, []int{27}
} }
func (m *UserGrantSearchRequest) XXX_Unmarshal(b []byte) error { func (m *UserGrantSearchRequest) XXX_Unmarshal(b []byte) error {
@ -2246,7 +2285,7 @@ func (m *UserGrantSearchQuery) Reset() { *m = UserGrantSearchQuery{} }
func (m *UserGrantSearchQuery) String() string { return proto.CompactTextString(m) } func (m *UserGrantSearchQuery) String() string { return proto.CompactTextString(m) }
func (*UserGrantSearchQuery) ProtoMessage() {} func (*UserGrantSearchQuery) ProtoMessage() {}
func (*UserGrantSearchQuery) Descriptor() ([]byte, []int) { func (*UserGrantSearchQuery) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{27} return fileDescriptor_8bbd6f3875b0e874, []int{28}
} }
func (m *UserGrantSearchQuery) XXX_Unmarshal(b []byte) error { func (m *UserGrantSearchQuery) XXX_Unmarshal(b []byte) error {
@ -2304,7 +2343,7 @@ func (m *UserGrantSearchResponse) Reset() { *m = UserGrantSearchResponse
func (m *UserGrantSearchResponse) String() string { return proto.CompactTextString(m) } func (m *UserGrantSearchResponse) String() string { return proto.CompactTextString(m) }
func (*UserGrantSearchResponse) ProtoMessage() {} func (*UserGrantSearchResponse) ProtoMessage() {}
func (*UserGrantSearchResponse) Descriptor() ([]byte, []int) { func (*UserGrantSearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{28} return fileDescriptor_8bbd6f3875b0e874, []int{29}
} }
func (m *UserGrantSearchResponse) XXX_Unmarshal(b []byte) error { func (m *UserGrantSearchResponse) XXX_Unmarshal(b []byte) error {
@ -2383,7 +2422,7 @@ func (m *UserGrantView) Reset() { *m = UserGrantView{} }
func (m *UserGrantView) String() string { return proto.CompactTextString(m) } func (m *UserGrantView) String() string { return proto.CompactTextString(m) }
func (*UserGrantView) ProtoMessage() {} func (*UserGrantView) ProtoMessage() {}
func (*UserGrantView) Descriptor() ([]byte, []int) { func (*UserGrantView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{29} return fileDescriptor_8bbd6f3875b0e874, []int{30}
} }
func (m *UserGrantView) XXX_Unmarshal(b []byte) error { func (m *UserGrantView) XXX_Unmarshal(b []byte) error {
@ -2460,7 +2499,7 @@ func (m *MyProjectOrgSearchRequest) Reset() { *m = MyProjectOrgSearchReq
func (m *MyProjectOrgSearchRequest) String() string { return proto.CompactTextString(m) } func (m *MyProjectOrgSearchRequest) String() string { return proto.CompactTextString(m) }
func (*MyProjectOrgSearchRequest) ProtoMessage() {} func (*MyProjectOrgSearchRequest) ProtoMessage() {}
func (*MyProjectOrgSearchRequest) Descriptor() ([]byte, []int) { func (*MyProjectOrgSearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{30} return fileDescriptor_8bbd6f3875b0e874, []int{31}
} }
func (m *MyProjectOrgSearchRequest) XXX_Unmarshal(b []byte) error { func (m *MyProjectOrgSearchRequest) XXX_Unmarshal(b []byte) error {
@ -2522,7 +2561,7 @@ func (m *MyProjectOrgSearchQuery) Reset() { *m = MyProjectOrgSearchQuery
func (m *MyProjectOrgSearchQuery) String() string { return proto.CompactTextString(m) } func (m *MyProjectOrgSearchQuery) String() string { return proto.CompactTextString(m) }
func (*MyProjectOrgSearchQuery) ProtoMessage() {} func (*MyProjectOrgSearchQuery) ProtoMessage() {}
func (*MyProjectOrgSearchQuery) Descriptor() ([]byte, []int) { func (*MyProjectOrgSearchQuery) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{31} return fileDescriptor_8bbd6f3875b0e874, []int{32}
} }
func (m *MyProjectOrgSearchQuery) XXX_Unmarshal(b []byte) error { func (m *MyProjectOrgSearchQuery) XXX_Unmarshal(b []byte) error {
@ -2578,7 +2617,7 @@ func (m *MyProjectOrgSearchResponse) Reset() { *m = MyProjectOrgSearchRe
func (m *MyProjectOrgSearchResponse) String() string { return proto.CompactTextString(m) } func (m *MyProjectOrgSearchResponse) String() string { return proto.CompactTextString(m) }
func (*MyProjectOrgSearchResponse) ProtoMessage() {} func (*MyProjectOrgSearchResponse) ProtoMessage() {}
func (*MyProjectOrgSearchResponse) Descriptor() ([]byte, []int) { func (*MyProjectOrgSearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{32} return fileDescriptor_8bbd6f3875b0e874, []int{33}
} }
func (m *MyProjectOrgSearchResponse) XXX_Unmarshal(b []byte) error { func (m *MyProjectOrgSearchResponse) XXX_Unmarshal(b []byte) error {
@ -2639,7 +2678,7 @@ func (m *Org) Reset() { *m = Org{} }
func (m *Org) String() string { return proto.CompactTextString(m) } func (m *Org) String() string { return proto.CompactTextString(m) }
func (*Org) ProtoMessage() {} func (*Org) ProtoMessage() {}
func (*Org) Descriptor() ([]byte, []int) { func (*Org) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{33} return fileDescriptor_8bbd6f3875b0e874, []int{34}
} }
func (m *Org) XXX_Unmarshal(b []byte) error { func (m *Org) XXX_Unmarshal(b []byte) error {
@ -2685,7 +2724,7 @@ func (m *MyPermissions) Reset() { *m = MyPermissions{} }
func (m *MyPermissions) String() string { return proto.CompactTextString(m) } func (m *MyPermissions) String() string { return proto.CompactTextString(m) }
func (*MyPermissions) ProtoMessage() {} func (*MyPermissions) ProtoMessage() {}
func (*MyPermissions) Descriptor() ([]byte, []int) { func (*MyPermissions) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{34} return fileDescriptor_8bbd6f3875b0e874, []int{35}
} }
func (m *MyPermissions) XXX_Unmarshal(b []byte) error { func (m *MyPermissions) XXX_Unmarshal(b []byte) error {
@ -2726,7 +2765,7 @@ func (m *ChangesRequest) Reset() { *m = ChangesRequest{} }
func (m *ChangesRequest) String() string { return proto.CompactTextString(m) } func (m *ChangesRequest) String() string { return proto.CompactTextString(m) }
func (*ChangesRequest) ProtoMessage() {} func (*ChangesRequest) ProtoMessage() {}
func (*ChangesRequest) Descriptor() ([]byte, []int) { func (*ChangesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{35} return fileDescriptor_8bbd6f3875b0e874, []int{36}
} }
func (m *ChangesRequest) XXX_Unmarshal(b []byte) error { func (m *ChangesRequest) XXX_Unmarshal(b []byte) error {
@ -2781,7 +2820,7 @@ func (m *Changes) Reset() { *m = Changes{} }
func (m *Changes) String() string { return proto.CompactTextString(m) } func (m *Changes) String() string { return proto.CompactTextString(m) }
func (*Changes) ProtoMessage() {} func (*Changes) ProtoMessage() {}
func (*Changes) Descriptor() ([]byte, []int) { func (*Changes) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{36} return fileDescriptor_8bbd6f3875b0e874, []int{37}
} }
func (m *Changes) XXX_Unmarshal(b []byte) error { func (m *Changes) XXX_Unmarshal(b []byte) error {
@ -2839,7 +2878,7 @@ func (m *Change) Reset() { *m = Change{} }
func (m *Change) String() string { return proto.CompactTextString(m) } func (m *Change) String() string { return proto.CompactTextString(m) }
func (*Change) ProtoMessage() {} func (*Change) ProtoMessage() {}
func (*Change) Descriptor() ([]byte, []int) { func (*Change) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{37} return fileDescriptor_8bbd6f3875b0e874, []int{38}
} }
func (m *Change) XXX_Unmarshal(b []byte) error { func (m *Change) XXX_Unmarshal(b []byte) error {
@ -2923,7 +2962,7 @@ func (m *PasswordComplexityPolicy) Reset() { *m = PasswordComplexityPoli
func (m *PasswordComplexityPolicy) String() string { return proto.CompactTextString(m) } func (m *PasswordComplexityPolicy) String() string { return proto.CompactTextString(m) }
func (*PasswordComplexityPolicy) ProtoMessage() {} func (*PasswordComplexityPolicy) ProtoMessage() {}
func (*PasswordComplexityPolicy) Descriptor() ([]byte, []int) { func (*PasswordComplexityPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{38} return fileDescriptor_8bbd6f3875b0e874, []int{39}
} }
func (m *PasswordComplexityPolicy) XXX_Unmarshal(b []byte) error { func (m *PasswordComplexityPolicy) XXX_Unmarshal(b []byte) error {
@ -3037,6 +3076,7 @@ func init() {
proto.RegisterType((*UserProfile)(nil), "caos.zitadel.auth.api.v1.UserProfile") proto.RegisterType((*UserProfile)(nil), "caos.zitadel.auth.api.v1.UserProfile")
proto.RegisterType((*UserProfileView)(nil), "caos.zitadel.auth.api.v1.UserProfileView") proto.RegisterType((*UserProfileView)(nil), "caos.zitadel.auth.api.v1.UserProfileView")
proto.RegisterType((*UpdateUserProfileRequest)(nil), "caos.zitadel.auth.api.v1.UpdateUserProfileRequest") proto.RegisterType((*UpdateUserProfileRequest)(nil), "caos.zitadel.auth.api.v1.UpdateUserProfileRequest")
proto.RegisterType((*ChangeUserNameRequest)(nil), "caos.zitadel.auth.api.v1.ChangeUserNameRequest")
proto.RegisterType((*UserEmail)(nil), "caos.zitadel.auth.api.v1.UserEmail") proto.RegisterType((*UserEmail)(nil), "caos.zitadel.auth.api.v1.UserEmail")
proto.RegisterType((*UserEmailView)(nil), "caos.zitadel.auth.api.v1.UserEmailView") proto.RegisterType((*UserEmailView)(nil), "caos.zitadel.auth.api.v1.UserEmailView")
proto.RegisterType((*VerifyMyUserEmailRequest)(nil), "caos.zitadel.auth.api.v1.VerifyMyUserEmailRequest") proto.RegisterType((*VerifyMyUserEmailRequest)(nil), "caos.zitadel.auth.api.v1.VerifyMyUserEmailRequest")
@ -3075,239 +3115,242 @@ func init() {
func init() { proto.RegisterFile("auth.proto", fileDescriptor_8bbd6f3875b0e874) } func init() { proto.RegisterFile("auth.proto", fileDescriptor_8bbd6f3875b0e874) }
var fileDescriptor_8bbd6f3875b0e874 = []byte{ var fileDescriptor_8bbd6f3875b0e874 = []byte{
// 3566 bytes of a gzipped FileDescriptorProto // 3616 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x5f, 0x6f, 0x1b, 0xd7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x5f, 0x6f, 0x1b, 0x57,
0x95, 0xf7, 0x90, 0x94, 0x44, 0x1e, 0x4a, 0x14, 0x75, 0x2d, 0x4b, 0x14, 0x65, 0xd9, 0xf2, 0x38, 0x76, 0xf7, 0x90, 0x94, 0x44, 0x1e, 0x4a, 0x14, 0x75, 0x2d, 0x4b, 0x14, 0x65, 0xd9, 0xf4, 0x38,
0x8e, 0x65, 0xc6, 0x16, 0x63, 0x25, 0xc1, 0xda, 0x0e, 0xb0, 0x01, 0x2d, 0xd2, 0x12, 0xd7, 0xe2, 0x8e, 0x65, 0xc6, 0x16, 0x6d, 0x25, 0x41, 0x6d, 0x07, 0x48, 0x40, 0x8b, 0xb4, 0xc4, 0x5a, 0xfc,
0x9f, 0x0c, 0x29, 0x67, 0x1d, 0x60, 0x41, 0x8c, 0x38, 0x57, 0xd4, 0x24, 0x43, 0x0e, 0x33, 0x33, 0x93, 0x21, 0xe5, 0xd4, 0x01, 0x0a, 0x62, 0xc4, 0xb9, 0xa2, 0x26, 0x19, 0x72, 0x98, 0x99, 0xa1,
0x94, 0x96, 0x01, 0x36, 0xc0, 0x7a, 0x17, 0x9b, 0x5d, 0x60, 0xb3, 0xbb, 0xc8, 0x2e, 0x16, 0x28, 0x54, 0x06, 0x68, 0x80, 0xa6, 0x45, 0xd3, 0x02, 0x4d, 0x5b, 0xa4, 0x45, 0x81, 0xa2, 0xe8, 0x43,
0x8a, 0x3e, 0x14, 0x68, 0x8b, 0x3e, 0x14, 0xed, 0x43, 0xd1, 0x02, 0x45, 0xfb, 0x01, 0xfa, 0xd2, 0x81, 0xb6, 0xe8, 0x43, 0xd1, 0x3e, 0x14, 0x2d, 0x50, 0xb4, 0x1f, 0xa0, 0x2f, 0x7d, 0x58, 0x2c,
0x87, 0xa2, 0x40, 0x3f, 0x40, 0xd1, 0xaf, 0x50, 0x14, 0x4d, 0x5f, 0x8a, 0xfb, 0x67, 0x86, 0xc3, 0xb0, 0x1f, 0x60, 0xb1, 0x5f, 0x61, 0xb1, 0xd8, 0xec, 0xcb, 0xe2, 0xfe, 0x99, 0xe1, 0x70, 0x86,
0x19, 0x0e, 0x49, 0xd9, 0x4d, 0x1b, 0x04, 0x79, 0x12, 0xef, 0xf9, 0x77, 0xcf, 0x3d, 0xe7, 0x77, 0x43, 0x52, 0xf6, 0x66, 0x37, 0x08, 0xf2, 0x24, 0xde, 0xf3, 0xef, 0xfe, 0xee, 0x39, 0xe7, 0xde,
0xef, 0x3d, 0x73, 0x8f, 0x00, 0xe4, 0x9e, 0x75, 0xb2, 0xdd, 0x35, 0x74, 0x4b, 0x47, 0xa9, 0xa6, 0x7b, 0xe6, 0x1e, 0x01, 0xc8, 0x7d, 0xeb, 0x74, 0xa7, 0x67, 0xe8, 0x96, 0x8e, 0x52, 0x2d, 0x59,
0xac, 0x9b, 0xdb, 0x1f, 0xaa, 0x96, 0xac, 0x60, 0x6d, 0x9b, 0x32, 0xe4, 0xae, 0xba, 0x7d, 0x7a, 0x37, 0x77, 0x3e, 0x55, 0x2d, 0x59, 0xc1, 0xda, 0x0e, 0x65, 0xc8, 0x3d, 0x75, 0xe7, 0xec, 0x41,
0x37, 0x7d, 0xb9, 0xa5, 0xeb, 0x2d, 0x0d, 0x67, 0xe5, 0xae, 0x9a, 0x95, 0x3b, 0x1d, 0xdd, 0x92, 0xfa, 0x6a, 0x5b, 0xd7, 0xdb, 0x1a, 0xce, 0xc9, 0x3d, 0x35, 0x27, 0x77, 0xbb, 0xba, 0x25, 0x5b,
0x2d, 0x55, 0xef, 0x98, 0x4c, 0x2f, 0xbd, 0xce, 0xb9, 0x74, 0x74, 0xd4, 0x3b, 0xce, 0xe2, 0x76, 0xaa, 0xde, 0x35, 0x99, 0x5e, 0x7a, 0x93, 0x73, 0xe9, 0xe8, 0xb8, 0x7f, 0x92, 0xc3, 0x9d, 0x9e,
0xd7, 0xea, 0x73, 0xe6, 0x65, 0x2f, 0xd3, 0xb4, 0x8c, 0x5e, 0xd3, 0xe2, 0xdc, 0xab, 0x5e, 0xae, 0x35, 0xe0, 0xcc, 0xab, 0x5e, 0xa6, 0x69, 0x19, 0xfd, 0x96, 0xc5, 0xb9, 0xd7, 0xbd, 0x5c, 0x4b,
0xa5, 0xb6, 0xb1, 0x69, 0xc9, 0xed, 0x2e, 0x17, 0x58, 0x3d, 0x95, 0x35, 0x55, 0x91, 0x2d, 0x9c, 0xed, 0x60, 0xd3, 0x92, 0x3b, 0x3d, 0x2e, 0xb0, 0x7e, 0x26, 0x6b, 0xaa, 0x22, 0x5b, 0x38, 0x67,
0xb5, 0x7f, 0x70, 0xc6, 0x6d, 0xfa, 0xa7, 0x79, 0xa7, 0x85, 0x3b, 0x77, 0xcc, 0x33, 0xb9, 0xd5, 0xff, 0xe0, 0x8c, 0xbb, 0xf4, 0x4f, 0xeb, 0x5e, 0x1b, 0x77, 0xef, 0x99, 0xe7, 0x72, 0xbb, 0x8d,
0xc2, 0x46, 0x56, 0xef, 0x52, 0xb7, 0x46, 0xb8, 0x98, 0x22, 0xab, 0x61, 0x6c, 0x5b, 0x8a, 0x73, 0x8d, 0x9c, 0xde, 0xa3, 0xb0, 0xc6, 0x40, 0x4c, 0x91, 0xd5, 0x30, 0xb6, 0x2d, 0xc5, 0x39, 0x97,
0x2e, 0xd2, 0x3f, 0xd9, 0x36, 0x36, 0x4d, 0xb9, 0xc5, 0x8d, 0x8b, 0x47, 0x90, 0x3c, 0x34, 0xb1, 0xe9, 0x9f, 0x5c, 0x07, 0x9b, 0xa6, 0xdc, 0xe6, 0xc6, 0xc5, 0x63, 0x48, 0x1e, 0x99, 0xd8, 0xa8,
0x51, 0xc3, 0xa6, 0xa9, 0xea, 0x9d, 0x27, 0x2a, 0x3e, 0x33, 0x51, 0x19, 0x16, 0x7a, 0x26, 0x36, 0x63, 0xd3, 0x54, 0xf5, 0xee, 0x73, 0x15, 0x9f, 0x9b, 0xa8, 0x02, 0x4b, 0x7d, 0x13, 0x1b, 0x4d,
0x1a, 0x26, 0x23, 0x9a, 0x29, 0x61, 0x33, 0xbc, 0x15, 0xdf, 0xb9, 0xb5, 0x1d, 0x14, 0xb5, 0x6d, 0x93, 0x11, 0xcd, 0x94, 0x90, 0x09, 0x6f, 0xc7, 0x77, 0xef, 0xec, 0x04, 0x79, 0x6d, 0xc7, 0x63,
0x8f, 0x09, 0x69, 0xbe, 0x37, 0x20, 0x98, 0xe2, 0xd7, 0x43, 0xb0, 0xe8, 0x91, 0x40, 0x09, 0x08, 0x42, 0x5a, 0xec, 0x0f, 0x09, 0xa6, 0xf8, 0x77, 0x21, 0x58, 0xf6, 0x48, 0xa0, 0x04, 0x84, 0x54,
0xa9, 0x4a, 0x4a, 0xd8, 0x14, 0xb6, 0x62, 0x52, 0x48, 0x55, 0xd0, 0x1a, 0x44, 0xe5, 0x16, 0xee, 0x25, 0x25, 0x64, 0x84, 0xed, 0x98, 0x14, 0x52, 0x15, 0xb4, 0x01, 0x51, 0xb9, 0x8d, 0xbb, 0x56,
0x58, 0x0d, 0x55, 0x49, 0x85, 0x28, 0x75, 0x8e, 0x8e, 0x8b, 0x0a, 0x2a, 0xb2, 0xd4, 0x35, 0x4c, 0x53, 0x55, 0x52, 0x21, 0x4a, 0x5d, 0xa0, 0xe3, 0x92, 0x82, 0x4a, 0x2c, 0x74, 0x4d, 0xd3, 0x92,
0x4b, 0xb6, 0x70, 0x2a, 0xbc, 0x29, 0x6c, 0x25, 0x76, 0x32, 0x53, 0xf9, 0x52, 0x23, 0x1a, 0x52, 0x2d, 0x9c, 0x0a, 0x67, 0x84, 0xed, 0xc4, 0x6e, 0x76, 0x26, 0x2c, 0x75, 0xa2, 0x21, 0xc5, 0x08,
0x8c, 0x70, 0xe9, 0x4f, 0xb4, 0x0a, 0x73, 0x74, 0x65, 0xaa, 0x92, 0x8a, 0xd0, 0x49, 0x66, 0xc9, 0x97, 0xfe, 0x44, 0xeb, 0xb0, 0x40, 0x57, 0xa6, 0x2a, 0xa9, 0x08, 0x9d, 0x64, 0x9e, 0x0c, 0x4b,
0xb0, 0xa8, 0xa0, 0x75, 0x88, 0x51, 0x46, 0x47, 0x6e, 0xe3, 0xd4, 0x0c, 0x65, 0x45, 0x09, 0xa1, 0x0a, 0xda, 0x84, 0x18, 0x65, 0x74, 0xe5, 0x0e, 0x4e, 0xcd, 0x51, 0x56, 0x94, 0x10, 0x2a, 0x72,
0x2c, 0xb7, 0x31, 0x4a, 0x43, 0xd4, 0xc4, 0x1f, 0xf4, 0x70, 0xa7, 0x89, 0x53, 0xb3, 0x9b, 0xc2, 0x07, 0xa3, 0x34, 0x44, 0x4d, 0xfc, 0x49, 0x1f, 0x77, 0x5b, 0x38, 0x35, 0x9f, 0x11, 0xb6, 0x23,
0x56, 0x44, 0x72, 0xc6, 0x68, 0x03, 0x40, 0xd3, 0x5b, 0x6a, 0x87, 0x69, 0xce, 0x51, 0xcd, 0x18, 0x92, 0x33, 0x46, 0x5b, 0x00, 0x9a, 0xde, 0x56, 0xbb, 0x4c, 0x73, 0x81, 0x6a, 0xc6, 0x28, 0x85,
0xa5, 0x50, 0xd5, 0x6b, 0x30, 0xaf, 0xa8, 0x66, 0x57, 0x93, 0xfb, 0x4c, 0x20, 0x4a, 0x05, 0xe2, 0xaa, 0xde, 0x80, 0x45, 0x45, 0x35, 0x7b, 0x9a, 0x3c, 0x60, 0x02, 0x51, 0x2a, 0x10, 0xe7, 0x34,
0x9c, 0x46, 0x44, 0xc4, 0x8f, 0xa3, 0x10, 0x25, 0x3e, 0x8f, 0x0c, 0xcb, 0x7d, 0x98, 0x61, 0xcb, 0x22, 0x22, 0x7e, 0x11, 0x85, 0x28, 0xc1, 0x3c, 0xd6, 0x2d, 0x8f, 0x60, 0x8e, 0x2d, 0x3b, 0x44,
0x0e, 0xd1, 0x65, 0x5f, 0x9f, 0xb0, 0x6c, 0xba, 0x5e, 0xa6, 0x81, 0xde, 0x82, 0x85, 0xa6, 0x81, 0x97, 0x7d, 0x73, 0xca, 0xb2, 0xe9, 0x7a, 0x99, 0x06, 0x7a, 0x0f, 0x96, 0x5a, 0x06, 0xa6, 0xb9,
0x29, 0x36, 0x1a, 0x8a, 0x1d, 0xb9, 0xf8, 0x4e, 0x7a, 0x9b, 0x01, 0x71, 0xdb, 0x06, 0xe2, 0x76, 0xd1, 0x54, 0x6c, 0xcf, 0xc5, 0x77, 0xd3, 0x3b, 0x2c, 0x11, 0x77, 0xec, 0x44, 0xdc, 0x69, 0xd8,
0xdd, 0x06, 0xa2, 0x34, 0x6f, 0x2b, 0xe4, 0x89, 0x81, 0x37, 0x21, 0xde, 0x3c, 0x91, 0x3b, 0x2d, 0x89, 0x28, 0x2d, 0xda, 0x0a, 0x05, 0x62, 0xe0, 0x1d, 0x88, 0xb7, 0x4e, 0xe5, 0x6e, 0x1b, 0x33,
0xcc, 0xd4, 0x23, 0x13, 0xd5, 0x81, 0x89, 0x53, 0xe5, 0xfb, 0x00, 0x9a, 0x6c, 0x5a, 0x0d, 0x1a, 0xf5, 0xc8, 0x54, 0x75, 0x60, 0xe2, 0x54, 0xf9, 0x11, 0x80, 0x26, 0x9b, 0x56, 0x93, 0xba, 0x82,
0x0a, 0x1a, 0xd1, 0xf1, 0xba, 0x31, 0x22, 0x7d, 0x40, 0x84, 0x51, 0x01, 0x92, 0x5d, 0xd9, 0x34, 0x7a, 0x74, 0xb2, 0x6e, 0x8c, 0x48, 0x1f, 0x12, 0x61, 0x54, 0x84, 0x64, 0x4f, 0x36, 0xcd, 0x73,
0xcf, 0x74, 0x43, 0x69, 0x30, 0x8b, 0x0a, 0x0d, 0xfb, 0x78, 0x03, 0x8b, 0xb6, 0xce, 0x2e, 0x53, 0xdd, 0x50, 0x9a, 0xcc, 0xa2, 0x42, 0xdd, 0x3e, 0xd9, 0xc0, 0xb2, 0xad, 0xb3, 0xc7, 0x54, 0x46,
0x19, 0x4e, 0xe9, 0x9c, 0x27, 0xa5, 0x1b, 0x00, 0xc7, 0xaa, 0x61, 0x5a, 0xee, 0xac, 0xc4, 0x28, 0x43, 0xba, 0xe0, 0x09, 0xe9, 0x16, 0xc0, 0x89, 0x6a, 0x98, 0x96, 0x3b, 0x2a, 0x31, 0x4a, 0xa1,
0x85, 0xb2, 0xd7, 0x81, 0xfa, 0xc3, 0xb8, 0x31, 0xa6, 0x4b, 0x08, 0x23, 0x73, 0x0a, 0xbe, 0x9c, 0xec, 0x4d, 0xa0, 0x78, 0x18, 0x37, 0xc6, 0x74, 0x09, 0x61, 0x6c, 0x4c, 0xc1, 0x17, 0x53, 0xa2,
0x12, 0xfd, 0x8e, 0xda, 0x7c, 0x9f, 0xf1, 0xe3, 0x4c, 0x9f, 0x10, 0x28, 0xf3, 0x0e, 0xa0, 0xae, 0xdf, 0x55, 0x5b, 0x1f, 0x33, 0x7e, 0x9c, 0xe9, 0x13, 0x02, 0x65, 0xde, 0x03, 0xd4, 0x33, 0xf0,
0x81, 0x8f, 0xb1, 0x61, 0x60, 0xa5, 0xa1, 0xc9, 0x9d, 0x56, 0x4f, 0x6e, 0xe1, 0xd4, 0x3c, 0x95, 0x09, 0x36, 0x0c, 0xac, 0x34, 0x35, 0xb9, 0xdb, 0xee, 0xcb, 0x6d, 0x9c, 0x5a, 0xa4, 0x52, 0x2b,
0x5a, 0x72, 0x38, 0x07, 0x9c, 0x81, 0xee, 0xc1, 0x6c, 0x0b, 0x77, 0x14, 0x6c, 0xa4, 0x16, 0x28, 0x0e, 0xe7, 0x90, 0x33, 0xd0, 0x43, 0x98, 0x6f, 0xe3, 0xae, 0x82, 0x8d, 0xd4, 0x12, 0xcd, 0x81,
0x06, 0x36, 0x83, 0x31, 0xb0, 0x47, 0xe5, 0x24, 0x2e, 0x8f, 0x96, 0x61, 0x06, 0xb7, 0x65, 0x55, 0x4c, 0x70, 0x0e, 0xec, 0x53, 0x39, 0x89, 0xcb, 0xa3, 0x55, 0x98, 0xc3, 0x1d, 0x59, 0xd5, 0x52,
0x4b, 0x25, 0xa8, 0x6d, 0x36, 0x40, 0x19, 0x58, 0x52, 0xcd, 0x06, 0xfd, 0xdd, 0x38, 0xc5, 0x86, 0x09, 0x6a, 0x9b, 0x0d, 0x50, 0x16, 0x56, 0x54, 0xb3, 0x49, 0x7f, 0x37, 0xcf, 0xb0, 0xa1, 0x9e,
0x7a, 0xac, 0x62, 0x25, 0xb5, 0xb8, 0x29, 0x6c, 0x45, 0xa5, 0x45, 0xd5, 0x2c, 0x10, 0xfa, 0x13, 0xa8, 0x58, 0x49, 0x2d, 0x67, 0x84, 0xed, 0xa8, 0xb4, 0xac, 0x9a, 0x45, 0x42, 0x7f, 0xce, 0xc9,
0x4e, 0x26, 0x16, 0xba, 0x27, 0x7a, 0x07, 0xa7, 0x92, 0xcc, 0x02, 0x1d, 0x70, 0x0b, 0xf4, 0xf7, 0xc4, 0x42, 0xef, 0x54, 0xef, 0xe2, 0x54, 0x92, 0x59, 0xa0, 0x03, 0x6e, 0x81, 0xfe, 0x1e, 0x5a,
0xc0, 0xc2, 0x92, 0x6d, 0xa1, 0x4a, 0xe8, 0x8e, 0x85, 0x14, 0xcc, 0x35, 0xf5, 0x5e, 0xc7, 0x32, 0x58, 0xb1, 0x2d, 0xd4, 0x08, 0xdd, 0xb1, 0x90, 0x82, 0x85, 0x96, 0xde, 0xef, 0x5a, 0xc6, 0x20,
0xfa, 0x29, 0xc4, 0xb6, 0x35, 0x1f, 0x92, 0x5d, 0xa5, 0xe9, 0x4d, 0x59, 0x53, 0xad, 0x7e, 0xea, 0x85, 0xd8, 0xb6, 0xe6, 0x43, 0xb2, 0xab, 0x34, 0xbd, 0x25, 0x6b, 0xaa, 0x35, 0x48, 0x5d, 0xe6,
0x22, 0x0f, 0x31, 0x1f, 0xa3, 0xab, 0x10, 0xef, 0xea, 0xa6, 0x25, 0x6b, 0x8d, 0xa6, 0xae, 0xe0, 0x2e, 0xe6, 0x63, 0x74, 0x1d, 0xe2, 0x3d, 0xdd, 0xb4, 0x64, 0xad, 0xd9, 0xd2, 0x15, 0x9c, 0x5a,
0xd4, 0x32, 0x65, 0x03, 0x23, 0xed, 0xea, 0x0a, 0x46, 0x2b, 0x30, 0x6b, 0xe0, 0x96, 0xaa, 0x77, 0xa5, 0x6c, 0x60, 0xa4, 0x3d, 0x5d, 0xc1, 0x68, 0x0d, 0xe6, 0x0d, 0xdc, 0x56, 0xf5, 0x6e, 0xea,
0x52, 0x97, 0xd8, 0x3e, 0x66, 0x23, 0x74, 0x03, 0x12, 0xa6, 0x65, 0x60, 0x6c, 0x35, 0x64, 0x45, 0x0a, 0xdb, 0xc7, 0x6c, 0x84, 0x6e, 0x41, 0xc2, 0xb4, 0x0c, 0x8c, 0xad, 0xa6, 0xac, 0x28, 0x06,
0x31, 0xb0, 0x69, 0xa6, 0x56, 0x28, 0x7f, 0x81, 0x51, 0x73, 0x8c, 0x38, 0xb4, 0xa3, 0x57, 0x3d, 0x36, 0xcd, 0xd4, 0x1a, 0xe5, 0x2f, 0x31, 0x6a, 0x9e, 0x11, 0x47, 0x76, 0xf4, 0xba, 0x67, 0x47,
0x3b, 0xfa, 0x06, 0x24, 0x0c, 0x6c, 0xea, 0x3d, 0xa3, 0x89, 0x1b, 0xfa, 0x59, 0x07, 0x1b, 0xa9, 0xdf, 0x82, 0x84, 0x81, 0x4d, 0xbd, 0x6f, 0xb4, 0x70, 0x53, 0x3f, 0xef, 0x62, 0x23, 0x95, 0x62,
0x14, 0x33, 0x61, 0x53, 0x2b, 0x84, 0x48, 0x5c, 0x1c, 0x6c, 0x7c, 0x33, 0xb5, 0xb6, 0x19, 0x26, 0x26, 0x6c, 0x6a, 0x95, 0x10, 0x09, 0xc4, 0xe1, 0xc6, 0x37, 0x53, 0x1b, 0x99, 0x30, 0x81, 0xe8,
0x2e, 0x3a, 0x3b, 0xdf, 0x44, 0xaf, 0xc2, 0xb2, 0x2b, 0xcd, 0x83, 0x33, 0x22, 0x4d, 0xad, 0x0d, 0xec, 0x7c, 0x13, 0xdd, 0x87, 0x55, 0x57, 0x98, 0x87, 0x67, 0x44, 0x9a, 0x5a, 0x1b, 0xa6, 0xc0,
0x20, 0x70, 0x60, 0xab, 0x88, 0x3f, 0x09, 0x43, 0x9c, 0x6c, 0xe3, 0xaa, 0xa1, 0x1f, 0xab, 0x1a, 0xa1, 0xad, 0x22, 0xfe, 0x77, 0x18, 0xe2, 0x64, 0x1b, 0xd7, 0x0c, 0xfd, 0x44, 0xd5, 0xb0, 0xef,
0xf6, 0x1d, 0x06, 0x43, 0x88, 0x0e, 0x8d, 0x45, 0x74, 0x78, 0x2c, 0xa2, 0x23, 0x1e, 0x44, 0x0f, 0x30, 0x18, 0xc9, 0xe8, 0xd0, 0xc4, 0x8c, 0x0e, 0x4f, 0xcc, 0xe8, 0x88, 0x27, 0xa3, 0x47, 0xd2,
0xc1, 0x75, 0xc6, 0x03, 0x57, 0x2f, 0xdc, 0x67, 0xfd, 0x70, 0x1f, 0x8d, 0xe8, 0xb9, 0xc9, 0x88, 0x75, 0xce, 0x93, 0xae, 0xde, 0x74, 0x9f, 0xf7, 0xa7, 0xfb, 0xf8, 0x8c, 0x5e, 0x98, 0x9e, 0xd1,
0x8e, 0x9e, 0x13, 0xd1, 0xee, 0xbc, 0xc5, 0x3c, 0x79, 0xf3, 0x9d, 0x77, 0xf0, 0x62, 0xe7, 0x5d, 0xd1, 0x0b, 0x66, 0xb4, 0x3b, 0x6e, 0x31, 0x4f, 0xdc, 0x7c, 0xe7, 0x1d, 0xbc, 0xda, 0x79, 0x17,
0xfc, 0x3c, 0xe7, 0x9d, 0xf8, 0x3f, 0x11, 0x76, 0xc7, 0xf1, 0xdc, 0x8d, 0x3c, 0xcc, 0xbf, 0xca, 0xbf, 0xc8, 0x79, 0x27, 0xfe, 0x65, 0x84, 0xdd, 0x71, 0x3c, 0x76, 0x63, 0x0f, 0xf3, 0xef, 0xe3,
0xdf, 0x17, 0x36, 0x7f, 0xde, 0xed, 0x3c, 0x3f, 0xf5, 0x76, 0x5e, 0x08, 0xdc, 0xce, 0xff, 0x19, 0xf7, 0xad, 0x8d, 0x9f, 0x77, 0x3b, 0x2f, 0xce, 0xbc, 0x9d, 0x97, 0x02, 0xb7, 0xf3, 0x9f, 0x85,
0x82, 0xd4, 0x61, 0x97, 0xf8, 0xe2, 0x02, 0x86, 0x44, 0x96, 0x6b, 0x5a, 0xe8, 0xd6, 0x50, 0xba, 0x20, 0x75, 0xd4, 0x23, 0x58, 0x5c, 0x89, 0x21, 0x91, 0xe5, 0x9a, 0x16, 0xba, 0x33, 0x12, 0x6e,
0x29, 0x46, 0x1e, 0xc2, 0x67, 0x0f, 0xe7, 0x8c, 0x99, 0xa4, 0x90, 0xfa, 0xb9, 0xe0, 0x4e, 0xfd, 0x9a, 0x23, 0x4f, 0xe0, 0xeb, 0x27, 0x0b, 0xc6, 0x5c, 0x52, 0x48, 0xfd, 0x9f, 0xe0, 0x0e, 0xfd,
0x4d, 0x77, 0xea, 0x43, 0x3e, 0xc9, 0x01, 0x0c, 0x6e, 0xba, 0x61, 0x10, 0xf6, 0x0b, 0x3a, 0x90, 0x6d, 0x77, 0xe8, 0x43, 0x3e, 0xc9, 0x61, 0x1a, 0xdc, 0x76, 0xa7, 0x41, 0xd8, 0x2f, 0xe8, 0xa4,
0xb8, 0x3f, 0x32, 0xdf, 0x11, 0x9f, 0xc6, 0xd8, 0xdc, 0xcf, 0x9c, 0x2f, 0xf7, 0xe2, 0xef, 0x04, 0xc4, 0xa3, 0xb1, 0xf1, 0x8e, 0xf8, 0x34, 0x26, 0xc6, 0x7e, 0xee, 0x62, 0xb1, 0x17, 0xdf, 0x85,
0x88, 0x91, 0x40, 0xd0, 0x1b, 0xc6, 0xb7, 0x37, 0x9c, 0xbb, 0x2a, 0xe4, 0xbe, 0xab, 0xb6, 0xc0, 0x2b, 0xec, 0x6a, 0x3e, 0xe2, 0x29, 0x6f, 0xbb, 0xe2, 0x96, 0x7b, 0x5b, 0x30, 0x4f, 0x44, 0xbf,
0x7b, 0x25, 0xd1, 0x75, 0x8d, 0xb8, 0xa9, 0xdc, 0xc8, 0x8a, 0x4c, 0x42, 0xd6, 0xcc, 0x8b, 0x21, 0x7e, 0x32, 0x67, 0x84, 0x29, 0x68, 0x7b, 0x83, 0x88, 0x3f, 0x15, 0x20, 0x46, 0x54, 0xe9, 0x0d,
0x6b, 0xf6, 0x5c, 0x27, 0xc3, 0x1f, 0x04, 0x58, 0x70, 0xd6, 0x3d, 0xf2, 0x5c, 0xf8, 0xf2, 0xae, 0xe5, 0xdb, 0x5b, 0xce, 0x5d, 0x17, 0x72, 0xdf, 0x75, 0xdb, 0xe0, 0xbd, 0xd2, 0xa8, 0x5f, 0xc6,
0xfd, 0x01, 0xa4, 0xa8, 0x97, 0xfd, 0x52, 0xdf, 0x09, 0x81, 0xbd, 0x03, 0xae, 0x40, 0x84, 0x5e, 0xdc, 0x74, 0xee, 0xcc, 0x8c, 0x4c, 0xcb, 0xcc, 0xb9, 0x57, 0xcb, 0xcc, 0xf9, 0x0b, 0x9d, 0x2c,
0xee, 0x7e, 0xec, 0x53, 0xba, 0xb8, 0x0f, 0x2b, 0x4c, 0xd7, 0xa7, 0xe9, 0x8d, 0x9f, 0x6d, 0x29, 0x3f, 0x17, 0x60, 0xc9, 0x59, 0xf7, 0xd8, 0x73, 0xe5, 0xbb, 0xbb, 0xf6, 0xc7, 0x90, 0xa2, 0x28,
0x14, 0x60, 0xe9, 0x01, 0xac, 0x0c, 0xf6, 0xe1, 0x90, 0xa5, 0x4d, 0x3b, 0xf2, 0x7e, 0x27, 0x18, 0x07, 0xe5, 0x81, 0xe3, 0x02, 0x3b, 0x6d, 0xae, 0x41, 0x84, 0x16, 0x07, 0xfe, 0xbd, 0x43, 0xe9,
0x43, 0xfc, 0x3d, 0x47, 0x2d, 0xad, 0x6a, 0x46, 0x65, 0x8e, 0xd5, 0x47, 0xa1, 0x89, 0xf5, 0x51, 0xe2, 0x01, 0xac, 0x31, 0x5d, 0x9f, 0xa6, 0xd7, 0x7f, 0xb6, 0xa5, 0x50, 0x80, 0xa5, 0xc7, 0xb0,
0x78, 0x74, 0x7d, 0xf4, 0xc5, 0xcd, 0xdd, 0x1f, 0x39, 0x6e, 0x99, 0xbf, 0x01, 0xb8, 0xfd, 0xd2, 0x36, 0xdc, 0xc7, 0x23, 0x96, 0x32, 0xb6, 0xe7, 0xfd, 0x20, 0x18, 0x43, 0xfc, 0x19, 0xcf, 0x5a,
0xae, 0xfe, 0xbe, 0x1b, 0x33, 0xd4, 0x69, 0x1b, 0x33, 0x57, 0xed, 0x55, 0x33, 0xcc, 0xc4, 0x3e, 0x5a, 0x15, 0x8d, 0x8b, 0x1c, 0xab, 0xaf, 0x42, 0x53, 0xeb, 0xab, 0xf0, 0xf8, 0xfa, 0xea, 0xdb,
0x7b, 0x38, 0x6b, 0x44, 0x92, 0x42, 0x6a, 0x99, 0x07, 0x40, 0xbc, 0xe7, 0x06, 0xee, 0x90, 0xea, 0x1b, 0xbb, 0x5f, 0xf0, 0xbc, 0x65, 0x78, 0x03, 0xf2, 0xf6, 0x3b, 0xbb, 0xfa, 0x47, 0xee, 0x9c,
0x24, 0xc8, 0xff, 0x22, 0xc4, 0x0a, 0x40, 0xbb, 0x4c, 0xf5, 0x06, 0xdc, 0x55, 0x4c, 0x87, 0x82, 0xa1, 0xa0, 0xed, 0x9c, 0xb9, 0x6e, 0xaf, 0x9a, 0xe5, 0x4c, 0xec, 0xeb, 0x27, 0xf3, 0x46, 0x24,
0x8b, 0xe9, 0xf0, 0xf8, 0x62, 0x3a, 0x32, 0xa6, 0x98, 0x9e, 0x99, 0x50, 0x4c, 0xcf, 0x4e, 0x2a, 0x29, 0xa4, 0x56, 0xb9, 0x03, 0xc4, 0x87, 0xee, 0xc4, 0x1d, 0x51, 0x9d, 0x96, 0xf2, 0xff, 0x1f,
0xa6, 0xe7, 0x26, 0x25, 0x31, 0xfa, 0x62, 0x49, 0x8c, 0x9d, 0x2b, 0x89, 0xbf, 0xe4, 0x0f, 0x0f, 0x62, 0x05, 0xa4, 0x5d, 0xe6, 0x7a, 0x1d, 0xee, 0x2a, 0xc6, 0x43, 0xc1, 0xc5, 0x78, 0x78, 0x72,
0xdc, 0xd3, 0x91, 0x20, 0xfe, 0x2a, 0xa6, 0xe7, 0x8b, 0xe9, 0x6f, 0x04, 0x77, 0x55, 0xc3, 0xfd, 0x31, 0x1e, 0x99, 0x50, 0x8c, 0xcf, 0x4d, 0x29, 0xc6, 0xe7, 0xa7, 0x15, 0xe3, 0x0b, 0xd3, 0x82,
0xb5, 0x01, 0x2e, 0x0e, 0x82, 0xc9, 0x30, 0x1e, 0xfd, 0xec, 0xe1, 0x8c, 0x11, 0x26, 0x08, 0x77, 0x18, 0x7d, 0xb5, 0x20, 0xc6, 0x2e, 0x14, 0xc4, 0x1f, 0xf0, 0x87, 0x0b, 0x8e, 0x74, 0x6c, 0x12,
0xc2, 0xfa, 0x92, 0x2b, 0xac, 0x21, 0x8f, 0xd0, 0x20, 0xc0, 0xb7, 0x86, 0x03, 0x1c, 0xf6, 0x08, 0x7f, 0xef, 0xd3, 0x8b, 0xf9, 0xf4, 0xc7, 0x82, 0xbb, 0x2a, 0xe2, 0x78, 0xed, 0x04, 0x17, 0x87,
0xba, 0x43, 0xbd, 0xe9, 0x84, 0x3a, 0xe2, 0x91, 0xb2, 0x83, 0x9e, 0xf5, 0x05, 0x7d, 0xc6, 0x23, 0xce, 0xf4, 0x16, 0x02, 0x8e, 0x5b, 0x5f, 0x73, 0xb9, 0x35, 0xe4, 0xad, 0x16, 0x1c, 0x07, 0xdf,
0x39, 0x1c, 0x7e, 0xf1, 0x32, 0x40, 0x95, 0x3f, 0x27, 0x14, 0xf3, 0x5e, 0xc8, 0x88, 0xf7, 0x60, 0x19, 0x75, 0x70, 0xd8, 0x23, 0xe8, 0x76, 0x75, 0xc6, 0x71, 0x75, 0xc4, 0x23, 0x65, 0x3b, 0x3d,
0xd1, 0xe6, 0xda, 0x0b, 0xbf, 0x01, 0x51, 0xfb, 0xfd, 0xc1, 0x7b, 0x2e, 0xec, 0x4b, 0x0e, 0x4b, 0xe7, 0x73, 0xfa, 0x9c, 0x47, 0x72, 0xd4, 0xfd, 0xe2, 0x55, 0x80, 0x1a, 0x7f, 0x8e, 0x28, 0x15,
0xd4, 0x20, 0x51, 0x1d, 0x7a, 0xa6, 0x40, 0xb7, 0x61, 0x5e, 0xd7, 0x94, 0x46, 0xb0, 0x72, 0x5c, 0xbc, 0x29, 0x23, 0x3e, 0x84, 0x65, 0x9b, 0x3b, 0xac, 0x81, 0xa2, 0xf6, 0xfb, 0x85, 0xf7, 0x5c,
0xd7, 0x14, 0x5b, 0x87, 0x48, 0x77, 0xf0, 0xd9, 0x40, 0x3a, 0xe4, 0x93, 0xee, 0xe0, 0x33, 0x5b, 0x38, 0x90, 0x1c, 0x96, 0xa8, 0x41, 0xa2, 0x36, 0xf2, 0xcc, 0x81, 0xee, 0xc2, 0xa2, 0xae, 0x29,
0x5a, 0x14, 0x61, 0x9e, 0xdf, 0xbe, 0xc7, 0x72, 0xc5, 0xea, 0x22, 0xe4, 0x3e, 0x7e, 0xf8, 0x91, 0xcd, 0x60, 0xe5, 0xb8, 0xae, 0x29, 0xb6, 0x0e, 0x91, 0xee, 0xe2, 0xf3, 0xa1, 0x74, 0xc8, 0x27,
0x53, 0x84, 0xf9, 0x52, 0x4f, 0xb3, 0xd4, 0x47, 0x72, 0xd3, 0xd2, 0x0d, 0x13, 0xdd, 0x87, 0x48, 0xdd, 0xc5, 0xe7, 0xb6, 0xb4, 0x28, 0xc2, 0x22, 0xbf, 0x7d, 0x4f, 0xe4, 0xaa, 0xd5, 0x43, 0xc8,
0xfb, 0x58, 0xb6, 0x9f, 0xfc, 0x6e, 0x04, 0x57, 0x77, 0x2e, 0x2d, 0x89, 0xaa, 0x88, 0x1f, 0x41, 0x7d, 0xfc, 0xf0, 0x23, 0xa7, 0x04, 0x8b, 0xe5, 0xbe, 0x66, 0xa9, 0x4f, 0xe5, 0x96, 0xa5, 0x1b,
0xdc, 0x45, 0x44, 0x6f, 0x40, 0xc4, 0xea, 0x77, 0xd9, 0x6c, 0x89, 0x9d, 0x6b, 0x63, 0x2c, 0x1d, 0x26, 0x7a, 0x04, 0x91, 0xce, 0x89, 0x6c, 0x3f, 0x19, 0xde, 0x0a, 0xae, 0x0e, 0x5d, 0x5a, 0x12,
0xcb, 0xf5, 0x7e, 0x17, 0x4b, 0x54, 0x1c, 0xdd, 0x1b, 0x7e, 0xf1, 0x12, 0xc7, 0xe8, 0x3d, 0xca, 0x55, 0x11, 0x3f, 0x83, 0xb8, 0x8b, 0x88, 0xde, 0x86, 0x88, 0x35, 0xe8, 0xb1, 0xd9, 0x12, 0xbb,
0xb9, 0x1f, 0xbc, 0xc4, 0x4f, 0x04, 0x48, 0xb0, 0x95, 0x4a, 0xd8, 0xec, 0xea, 0x1d, 0x73, 0xe8, 0x37, 0x26, 0x58, 0x3a, 0x91, 0x1b, 0x83, 0x1e, 0x96, 0xa8, 0x38, 0x7a, 0x38, 0xfa, 0x62, 0x26,
0xbd, 0x4f, 0x18, 0x7a, 0xef, 0x4b, 0x42, 0xb8, 0x67, 0xd8, 0x05, 0x17, 0xf9, 0x49, 0x36, 0xac, 0x4e, 0xd0, 0x7b, 0x9a, 0x77, 0x3f, 0x98, 0x89, 0x5f, 0x0a, 0x90, 0x60, 0x2b, 0x95, 0xb0, 0xd9,
0x89, 0x9b, 0x06, 0xb6, 0xf8, 0x5e, 0xe7, 0xa3, 0x81, 0x3f, 0x91, 0xf3, 0xfa, 0x23, 0x41, 0xa2, 0xd3, 0xbb, 0xe6, 0xc8, 0x7b, 0xa1, 0x30, 0xf2, 0x5e, 0x98, 0x84, 0x70, 0xdf, 0xb0, 0x0b, 0x2e,
0x52, 0xcc, 0xef, 0xee, 0x6a, 0x2a, 0xee, 0x58, 0xb9, 0x9e, 0x75, 0x42, 0xbe, 0xd3, 0x9a, 0x74, 0xf2, 0x93, 0x6c, 0x58, 0x13, 0xb7, 0x0c, 0x6c, 0xf1, 0xbd, 0xce, 0x47, 0x43, 0x3c, 0x91, 0x8b,
0x34, 0x70, 0x28, 0xca, 0x08, 0x45, 0x05, 0x5d, 0x87, 0x05, 0xce, 0xe4, 0x7e, 0x30, 0xe7, 0xe6, 0xe2, 0x91, 0x20, 0x51, 0x2d, 0x15, 0xf6, 0xf6, 0x34, 0x15, 0x77, 0xad, 0x7c, 0xdf, 0x3a, 0x25,
0x19, 0xb1, 0x46, 0x69, 0xe2, 0x3f, 0x87, 0x60, 0x85, 0xec, 0xbb, 0x3d, 0x43, 0x26, 0x34, 0xd9, 0xdf, 0x79, 0x2d, 0x3a, 0x1a, 0x02, 0x8a, 0x32, 0x42, 0x49, 0x41, 0x37, 0x61, 0x89, 0x33, 0x39,
0x68, 0x9e, 0xd8, 0x10, 0x5c, 0x81, 0x59, 0xfd, 0xf8, 0xd8, 0xc4, 0x16, 0xb5, 0x1c, 0x91, 0xf8, 0x0e, 0x06, 0x6e, 0x91, 0x11, 0xeb, 0x94, 0x26, 0xfe, 0x41, 0x08, 0xd6, 0xc8, 0xbe, 0xdb, 0x37,
0x88, 0xdc, 0xd2, 0x9a, 0xda, 0x56, 0x99, 0xbd, 0x88, 0xc4, 0x06, 0xe8, 0x1f, 0x20, 0x61, 0xea, 0x64, 0x42, 0x93, 0x8d, 0xd6, 0xa9, 0x9d, 0x82, 0x6b, 0x30, 0xaf, 0x9f, 0x9c, 0x98, 0xd8, 0xa2,
0x86, 0xa5, 0x76, 0x5a, 0x8d, 0xa6, 0xae, 0xf5, 0xda, 0x1d, 0xfe, 0xb0, 0x7a, 0x7b, 0xfc, 0x0b, 0x96, 0x23, 0x12, 0x1f, 0x91, 0x5b, 0x5a, 0x53, 0x3b, 0x2a, 0xb3, 0x17, 0x91, 0xd8, 0x00, 0xfd,
0xa3, 0x6b, 0xde, 0xc7, 0xb8, 0x4f, 0x37, 0xd0, 0x33, 0x21, 0xb4, 0x79, 0x41, 0x5a, 0xe0, 0xd6, 0x2e, 0x24, 0x4c, 0xdd, 0xb0, 0xd4, 0x6e, 0xbb, 0xd9, 0xd2, 0xb5, 0x7e, 0xa7, 0xcb, 0x1f, 0x66,
0x76, 0xa9, 0x31, 0x12, 0x5f, 0xd9, 0x6c, 0xd2, 0x98, 0x45, 0x25, 0xf2, 0x13, 0xed, 0xc3, 0xdc, 0xef, 0x4e, 0x7e, 0xa1, 0x74, 0xcd, 0xfb, 0x0c, 0x0f, 0xe8, 0x06, 0xfa, 0x5c, 0x08, 0x65, 0x2e,
0x07, 0x3d, 0x6c, 0xa8, 0x98, 0x6c, 0x3e, 0x82, 0xad, 0xed, 0xa9, 0x67, 0x7a, 0xbb, 0x87, 0x8d, 0x49, 0x4b, 0xdc, 0xda, 0x1e, 0x35, 0x46, 0xfc, 0x2b, 0x9b, 0x2d, 0xea, 0xb3, 0xa8, 0x44, 0x7e,
0xbe, 0x64, 0xab, 0x8b, 0x3f, 0x16, 0x60, 0x79, 0x94, 0x04, 0xda, 0x87, 0xf0, 0xfb, 0xb8, 0xcf, 0xa2, 0x03, 0x58, 0xf8, 0xa4, 0x8f, 0x0d, 0x15, 0x93, 0xcd, 0x47, 0x72, 0x6b, 0x67, 0xe6, 0x99,
0x01, 0xf7, 0xbc, 0x0b, 0x21, 0x26, 0xd0, 0xdf, 0xc2, 0x6c, 0x1b, 0x5b, 0x27, 0xba, 0xc2, 0x51, 0xde, 0xef, 0x63, 0x63, 0x20, 0xd9, 0xea, 0xe2, 0x7f, 0x09, 0xb0, 0x3a, 0x4e, 0x02, 0x1d, 0x40,
0xf8, 0x72, 0xb0, 0x31, 0x66, 0xa3, 0x44, 0xa5, 0x25, 0xae, 0x45, 0x62, 0x7e, 0x2a, 0x6b, 0x3d, 0xf8, 0x63, 0x3c, 0xe0, 0x09, 0xf7, 0xb2, 0x0b, 0x21, 0x26, 0xd0, 0xbb, 0x30, 0xdf, 0xc1, 0xd6,
0xfb, 0x3b, 0x9e, 0x0d, 0xc4, 0x6f, 0x84, 0x60, 0xd5, 0x97, 0x3c, 0x8e, 0xd4, 0xf3, 0x65, 0xef, 0xa9, 0xae, 0xf0, 0x2c, 0x7c, 0x3d, 0xd8, 0x18, 0xb3, 0x51, 0xa6, 0xd2, 0x12, 0xd7, 0x22, 0x3e,
0x1a, 0xcc, 0x5b, 0x3a, 0x39, 0x1c, 0x0d, 0x6c, 0xf6, 0x34, 0x06, 0xd9, 0x88, 0x14, 0xa7, 0x34, 0x3f, 0x93, 0xb5, 0xbe, 0xfd, 0x0e, 0xc0, 0x06, 0xe2, 0xdf, 0x87, 0x60, 0xdd, 0x17, 0x3c, 0x9e,
0x89, 0x92, 0xd0, 0x5b, 0xe4, 0x54, 0xa4, 0xcc, 0x08, 0x0d, 0xf7, 0xcd, 0x29, 0xe2, 0x41, 0xdf, 0xa9, 0x17, 0x8b, 0xde, 0x0d, 0x58, 0xb4, 0x74, 0x72, 0x38, 0x1a, 0xd8, 0xec, 0x6b, 0x2c, 0x65,
0xee, 0xb9, 0x1a, 0x7b, 0x14, 0xd0, 0x9b, 0xd8, 0x34, 0xb1, 0xd2, 0x70, 0x2e, 0xa3, 0x19, 0x3a, 0x23, 0x52, 0x9c, 0xd2, 0x24, 0x4a, 0x42, 0xef, 0x91, 0x53, 0x91, 0x32, 0x23, 0xd4, 0xdd, 0xb7,
0xd3, 0x92, 0xc3, 0xa9, 0xd9, 0xb7, 0x52, 0x0e, 0x12, 0xa7, 0x2a, 0x3e, 0x6b, 0x38, 0x6d, 0x8d, 0x67, 0xf0, 0x07, 0x7d, 0xfb, 0xe7, 0x6a, 0xec, 0x51, 0x41, 0x6f, 0x61, 0xd3, 0xc4, 0x4a, 0xd3,
0x29, 0x0a, 0xae, 0x05, 0xa2, 0xe1, 0x0c, 0xc5, 0x6f, 0xf3, 0x8a, 0xd3, 0xf1, 0x85, 0xac, 0xbe, 0xb9, 0x8c, 0xe6, 0xe8, 0x4c, 0x2b, 0x0e, 0xa7, 0x6e, 0xdf, 0x4a, 0x79, 0x48, 0x9c, 0xa9, 0xf8,
0x62, 0xb4, 0x8a, 0xf6, 0x66, 0x61, 0x03, 0x74, 0x19, 0x62, 0x55, 0x43, 0x7f, 0x0f, 0x37, 0xad, 0xbc, 0xe9, 0xb4, 0x45, 0x66, 0x28, 0xb8, 0x96, 0x88, 0x86, 0x33, 0x14, 0xff, 0x89, 0x57, 0x9c,
0xa2, 0xdd, 0x2c, 0x18, 0x10, 0x48, 0x24, 0x0f, 0xe9, 0x26, 0xb7, 0x37, 0x32, 0x1b, 0x11, 0x5b, 0x0e, 0x16, 0xb2, 0xfa, 0xaa, 0xd1, 0x2e, 0xd9, 0x9b, 0x85, 0x0d, 0xd0, 0x55, 0x88, 0xd5, 0x0c,
0x92, 0xae, 0x61, 0x93, 0xc6, 0x23, 0x26, 0xb1, 0x01, 0xb9, 0xfe, 0x2b, 0x46, 0xab, 0x3c, 0x78, 0xfd, 0x23, 0xdc, 0xb2, 0x4a, 0x76, 0xb3, 0x61, 0x48, 0x20, 0x9e, 0x3c, 0xa2, 0x9b, 0xdc, 0xde,
0x38, 0xb1, 0x87, 0x84, 0x43, 0x1d, 0x29, 0x2a, 0xfc, 0x8a, 0xb6, 0x87, 0xe2, 0x77, 0x05, 0x58, 0xc8, 0x6c, 0x44, 0x6c, 0x49, 0xba, 0x86, 0x4d, 0xea, 0x8f, 0x98, 0xc4, 0x06, 0xe4, 0xfa, 0xaf,
0x2b, 0xf5, 0xf9, 0x8c, 0x15, 0xa3, 0xf5, 0x22, 0xfb, 0xd0, 0xbf, 0x51, 0x1e, 0x7b, 0x37, 0xca, 0x1a, 0xed, 0xca, 0xf0, 0xe1, 0xc5, 0x1e, 0x12, 0x0e, 0x05, 0x52, 0x52, 0xf8, 0x15, 0x6d, 0x0f,
0xdd, 0x31, 0x47, 0x8e, 0xcf, 0x0b, 0xcf, 0x5e, 0xf9, 0x99, 0x00, 0xab, 0x01, 0x42, 0xe8, 0xb1, 0xc5, 0x7f, 0x11, 0x60, 0xa3, 0x3c, 0xe0, 0x33, 0x56, 0x8d, 0xf6, 0xab, 0xec, 0x43, 0xff, 0x46,
0x7b, 0xbb, 0x64, 0xcf, 0x33, 0xc9, 0x5f, 0x6c, 0xc7, 0x7c, 0x4b, 0x80, 0xf4, 0xa8, 0x48, 0x7f, 0x79, 0xe6, 0xdd, 0x28, 0x0f, 0x26, 0x1c, 0x39, 0x3e, 0x14, 0x9e, 0xbd, 0xf2, 0xbf, 0x02, 0xac,
0x5e, 0x9b, 0xe6, 0x0d, 0xcf, 0xa6, 0xd9, 0x08, 0x5e, 0x45, 0xc5, 0x68, 0xd9, 0x5b, 0x45, 0xbc, 0x07, 0x08, 0xa1, 0x67, 0xee, 0xed, 0x92, 0xbb, 0xc8, 0x24, 0xbf, 0xb6, 0x1d, 0xf3, 0x8f, 0x02,
0x05, 0xe1, 0x8a, 0xd1, 0xf2, 0x95, 0x96, 0x08, 0x22, 0xae, 0xa7, 0x3e, 0xfa, 0x5b, 0xbc, 0x0b, 0xa4, 0xc7, 0x79, 0xfa, 0x9b, 0xda, 0x34, 0x6f, 0x7b, 0x36, 0xcd, 0x56, 0xf0, 0x2a, 0xaa, 0x46,
0x0b, 0xa5, 0x7e, 0x15, 0x1b, 0x6d, 0x95, 0x35, 0xc7, 0xd0, 0x26, 0xc4, 0xbb, 0x83, 0x21, 0xbd, 0xdb, 0xde, 0x2a, 0xe2, 0x1d, 0x08, 0x57, 0x8d, 0xb6, 0xaf, 0xb4, 0x44, 0x10, 0x71, 0x3d, 0x15,
0x77, 0x63, 0x92, 0x9b, 0x24, 0xca, 0x90, 0x60, 0xc5, 0x82, 0x53, 0x66, 0x39, 0xeb, 0x13, 0xdc, 0xd2, 0xdf, 0xe2, 0x03, 0x58, 0x2a, 0x0f, 0x6a, 0xd8, 0xe8, 0xa8, 0xac, 0xb9, 0x86, 0x32, 0x10,
0xeb, 0xbb, 0x09, 0x8b, 0xf6, 0x36, 0x6d, 0xf0, 0xb0, 0xb0, 0xf5, 0x27, 0x6c, 0x72, 0x85, 0x85, 0xef, 0x0d, 0x87, 0xf4, 0xde, 0x8d, 0x49, 0x6e, 0x92, 0x28, 0x43, 0x82, 0x15, 0x0b, 0x4e, 0x99,
0x87, 0x63, 0x2e, 0xec, 0x60, 0x4e, 0x34, 0x61, 0x8e, 0x4f, 0x81, 0x1e, 0xc0, 0x1c, 0xab, 0xf6, 0xe5, 0xac, 0x4f, 0x70, 0xaf, 0xef, 0x36, 0x2c, 0xdb, 0xdb, 0xb4, 0xc9, 0xdd, 0xc2, 0xd6, 0x9f,
0xec, 0x1a, 0x60, 0xcc, 0x0b, 0x0f, 0xd3, 0x91, 0x6c, 0x05, 0x57, 0x3e, 0x42, 0xa3, 0xf3, 0x11, 0xb0, 0xc9, 0x55, 0xe6, 0x1e, 0x9e, 0x73, 0x61, 0x27, 0xe7, 0x44, 0x13, 0x16, 0xf8, 0x14, 0xe8,
0x76, 0xf9, 0x2b, 0xfe, 0x47, 0x08, 0x66, 0x79, 0x15, 0xe4, 0xa9, 0x48, 0x85, 0x73, 0x3d, 0xdd, 0x31, 0x2c, 0xb0, 0x6a, 0xcf, 0xae, 0x01, 0x26, 0xbc, 0x10, 0x31, 0x1d, 0xc9, 0x56, 0x70, 0xc5,
0xe5, 0x01, 0xf0, 0x29, 0xb9, 0x37, 0x69, 0xb9, 0x11, 0xa2, 0xba, 0xde, 0xc2, 0x85, 0xf9, 0x7b, 0x23, 0x34, 0x3e, 0x1e, 0x61, 0x17, 0x5e, 0xf1, 0x4f, 0x43, 0x30, 0xcf, 0xab, 0x20, 0x4f, 0x45,
0x40, 0xab, 0xcb, 0x0f, 0xb1, 0x52, 0x62, 0x3d, 0x50, 0x29, 0x46, 0x15, 0x49, 0xf5, 0x31, 0x54, 0x2a, 0x5c, 0xe8, 0xe9, 0xaf, 0x00, 0x80, 0xcf, 0xc8, 0xbd, 0x49, 0xcb, 0x8d, 0x10, 0xd5, 0xf5,
0x71, 0x87, 0x3d, 0x15, 0xf7, 0x3a, 0xc4, 0xb0, 0xa2, 0x5a, 0xba, 0xab, 0x71, 0x18, 0x65, 0x04, 0x16, 0x2e, 0x0c, 0xef, 0x21, 0xad, 0x2e, 0x3f, 0xc5, 0x4a, 0x99, 0xf5, 0x50, 0xa5, 0x18, 0x55,
0x76, 0xde, 0xb0, 0xdf, 0x76, 0xa5, 0xcf, 0x46, 0xe8, 0x15, 0x88, 0x28, 0xb2, 0x25, 0xf3, 0x63, 0x24, 0xd5, 0xc7, 0x48, 0xc5, 0x1d, 0xf6, 0x54, 0xdc, 0x9b, 0x10, 0xc3, 0x8a, 0x6a, 0xe9, 0xae,
0x70, 0xd5, 0xb7, 0x98, 0x1a, 0xed, 0x0e, 0x4b, 0x54, 0x48, 0xfc, 0x5e, 0x18, 0x52, 0x4e, 0x65, 0xc6, 0x63, 0x94, 0x11, 0xd8, 0x79, 0xc3, 0x7e, 0xdb, 0x95, 0x3e, 0x1b, 0xa1, 0x37, 0x20, 0xa2,
0xa8, 0xb7, 0xbb, 0x1a, 0xfe, 0x47, 0xd5, 0xea, 0x57, 0x75, 0x4d, 0x6d, 0xf6, 0x7d, 0xb8, 0xda, 0xc8, 0x96, 0xcc, 0x8f, 0xc1, 0x75, 0xdf, 0x62, 0xea, 0xb4, 0xbb, 0x2c, 0x51, 0x21, 0xf1, 0x5f,
0x84, 0xb8, 0x82, 0xcd, 0xa6, 0xa1, 0xd2, 0xf6, 0x2e, 0x87, 0x97, 0x9b, 0xf4, 0x57, 0xee, 0xfd, 0xc3, 0x90, 0x72, 0x2a, 0x43, 0xbd, 0xd3, 0xd3, 0xf0, 0xef, 0xa9, 0xd6, 0xa0, 0xa6, 0x6b, 0x6a,
0x6d, 0x00, 0xb4, 0xd5, 0x4e, 0x43, 0xc3, 0x9d, 0x96, 0x75, 0xc2, 0x6f, 0x8c, 0x58, 0x5b, 0xed, 0x6b, 0xe0, 0xcb, 0xab, 0x0c, 0xc4, 0x15, 0x6c, 0xb6, 0x0c, 0x95, 0xb6, 0x87, 0x79, 0x7a, 0xb9,
0x1c, 0x50, 0x02, 0x29, 0x74, 0x4e, 0x64, 0xb3, 0xa1, 0xe9, 0x67, 0xd8, 0x68, 0xca, 0x26, 0xfb, 0x49, 0xbf, 0xe1, 0xde, 0xe1, 0x16, 0x40, 0x47, 0xed, 0x36, 0x35, 0xdc, 0x6d, 0x5b, 0xa7, 0xfc,
0x32, 0x8f, 0x4a, 0xf3, 0x27, 0xb2, 0x79, 0x60, 0xd3, 0x6c, 0xa1, 0x5e, 0xb7, 0xcb, 0x85, 0xe6, 0xc6, 0x88, 0x75, 0xd4, 0xee, 0x21, 0x25, 0x90, 0x42, 0xe7, 0x54, 0x36, 0x9b, 0x9a, 0x7e, 0x8e,
0x1c, 0xa1, 0x43, 0x9b, 0x46, 0x26, 0x22, 0x42, 0x9d, 0x5e, 0xfb, 0x88, 0x3f, 0x46, 0x47, 0xa5, 0x8d, 0x96, 0x6c, 0xb2, 0x2f, 0xf3, 0xa8, 0xb4, 0x78, 0x2a, 0x9b, 0x87, 0x36, 0xcd, 0x16, 0xea,
0xd8, 0x89, 0x6c, 0x96, 0x29, 0xc1, 0x66, 0x9b, 0xfd, 0xf6, 0x91, 0xae, 0xd1, 0xcf, 0x1c, 0xc6, 0xf7, 0x7a, 0x5c, 0x68, 0xc1, 0x11, 0x3a, 0xb2, 0x69, 0x64, 0x22, 0x22, 0xd4, 0xed, 0x77, 0x8e,
0xae, 0x51, 0xc2, 0x50, 0xc6, 0xc1, 0xdf, 0xd6, 0x55, 0xcd, 0x86, 0x82, 0x8f, 0x65, 0x72, 0x18, 0xf9, 0x63, 0x76, 0x54, 0x8a, 0x9d, 0xca, 0x66, 0x85, 0x12, 0x6c, 0xb6, 0x39, 0xe8, 0x1c, 0xeb,
0xc4, 0x99, 0xaa, 0x6a, 0xe6, 0x19, 0x21, 0x63, 0x0c, 0x75, 0xcd, 0x59, 0x6f, 0x79, 0x13, 0x2e, 0x1a, 0xfd, 0xcc, 0x61, 0xec, 0x3a, 0x25, 0x8c, 0x44, 0x1c, 0xfc, 0x6d, 0x61, 0xd5, 0x6c, 0x2a,
0x1f, 0xd6, 0x0a, 0x52, 0xad, 0x50, 0xab, 0x15, 0x2b, 0xe5, 0x5a, 0x3d, 0x57, 0x2f, 0x34, 0x0e, 0xf8, 0x44, 0x26, 0x87, 0x41, 0x9c, 0xa9, 0xaa, 0x66, 0x81, 0x11, 0xb2, 0xc6, 0x48, 0xd7, 0x9d,
0xcb, 0xb5, 0x6a, 0x61, 0xb7, 0xf8, 0xa8, 0x58, 0xc8, 0x27, 0x2f, 0xa0, 0x75, 0x58, 0xf5, 0x49, 0xf5, 0xa6, 0x33, 0x70, 0xf5, 0xa8, 0x5e, 0x94, 0xea, 0xc5, 0x7a, 0xbd, 0x54, 0xad, 0xd4, 0x1b,
0xe4, 0x76, 0xeb, 0xc5, 0x27, 0x85, 0xa4, 0x80, 0xae, 0xc2, 0xba, 0x8f, 0x59, 0x2f, 0x48, 0xa5, 0xf9, 0x46, 0xb1, 0x79, 0x54, 0xa9, 0xd7, 0x8a, 0x7b, 0xa5, 0xa7, 0xa5, 0x62, 0x21, 0x79, 0x09,
0x62, 0x39, 0x57, 0x2f, 0xe4, 0x93, 0xa1, 0xcc, 0x07, 0x90, 0x24, 0xe5, 0xa4, 0x7d, 0xf8, 0x51, 0x6d, 0xc2, 0xba, 0x4f, 0x22, 0xbf, 0xd7, 0x28, 0x3d, 0x2f, 0x26, 0x05, 0x74, 0x1d, 0x36, 0x7d,
0xd0, 0xae, 0xc1, 0x25, 0x4a, 0x2b, 0xd4, 0xaa, 0x95, 0x72, 0xad, 0x50, 0x7f, 0x5a, 0x2d, 0x34, 0xcc, 0x46, 0x51, 0x2a, 0x97, 0x2a, 0xf9, 0x46, 0xb1, 0x90, 0x0c, 0x65, 0x3f, 0x81, 0x24, 0x29,
0x76, 0x2b, 0xf9, 0x42, 0xf2, 0x02, 0xda, 0x80, 0x35, 0x1f, 0xab, 0x98, 0x6f, 0xd4, 0x2b, 0x8f, 0x27, 0xed, 0xc3, 0x8f, 0x26, 0xed, 0x06, 0x5c, 0xa1, 0xb4, 0x62, 0xbd, 0x56, 0xad, 0xd4, 0x8b,
0x0b, 0xe5, 0xa4, 0x80, 0xae, 0xc3, 0xd5, 0x40, 0x36, 0x17, 0x0a, 0x65, 0x7e, 0xc0, 0x1f, 0xbf, 0x8d, 0x17, 0xb5, 0x62, 0x73, 0xaf, 0x5a, 0x28, 0x26, 0x2f, 0xa1, 0x2d, 0xd8, 0xf0, 0xb1, 0x4a,
0xd8, 0x02, 0xd7, 0xe0, 0x12, 0xf5, 0x70, 0xc4, 0xca, 0x96, 0x21, 0x39, 0x60, 0x39, 0x4b, 0x5a, 0x85, 0x66, 0xa3, 0xfa, 0xac, 0x58, 0x49, 0x0a, 0xe8, 0x26, 0x5c, 0x0f, 0x64, 0x73, 0xa1, 0x50,
0x01, 0x34, 0xa0, 0x16, 0xcb, 0x9c, 0x1e, 0x42, 0x97, 0x60, 0x69, 0x40, 0xcf, 0x17, 0x0e, 0x0a, 0xf6, 0xdf, 0xf9, 0xe3, 0x17, 0x5b, 0xe0, 0x06, 0x5c, 0xa1, 0x08, 0xc7, 0xac, 0x6c, 0x15, 0x92,
0x64, 0x81, 0xe1, 0x61, 0x23, 0x07, 0x95, 0xdd, 0xc7, 0x85, 0x7c, 0x32, 0x32, 0x2c, 0x5c, 0x3b, 0x43, 0x96, 0xb3, 0xa4, 0x35, 0x40, 0x43, 0x6a, 0xa9, 0xc2, 0xe9, 0x21, 0x74, 0x05, 0x56, 0x86,
0xac, 0x55, 0x0b, 0xe5, 0x7c, 0x72, 0x66, 0x98, 0x5c, 0x2c, 0x17, 0xeb, 0xc5, 0xdc, 0x41, 0x72, 0xf4, 0x42, 0xf1, 0xb0, 0x48, 0x16, 0x18, 0x1e, 0x35, 0x72, 0x58, 0xdd, 0x7b, 0x56, 0x2c, 0x24,
0x36, 0xf3, 0xf7, 0x30, 0xcb, 0x9e, 0x9d, 0xc9, 0xe4, 0x7b, 0x85, 0x72, 0xbe, 0x20, 0x79, 0x5c, 0x23, 0xa3, 0xc2, 0xf5, 0xa3, 0x7a, 0xad, 0x58, 0x29, 0x24, 0xe7, 0x46, 0xc9, 0xa5, 0x4a, 0xa9,
0x5d, 0x82, 0x05, 0x4e, 0x7f, 0x54, 0x28, 0xe5, 0x0e, 0x88, 0x9f, 0x8b, 0x10, 0xe7, 0x24, 0x4a, 0x51, 0xca, 0x1f, 0x26, 0xe7, 0xb3, 0xbf, 0x03, 0xf3, 0xec, 0xd9, 0x9a, 0x4c, 0xbe, 0x5f, 0xac,
0x08, 0x21, 0x04, 0x09, 0x4e, 0xc8, 0x17, 0x9f, 0x90, 0x9c, 0x24, 0xc3, 0x99, 0x3c, 0xcc, 0xf1, 0x14, 0x8a, 0x92, 0x07, 0xea, 0x0a, 0x2c, 0x71, 0xfa, 0xd3, 0x62, 0x39, 0x7f, 0x48, 0x70, 0x2e,
0x0f, 0x15, 0xb4, 0x0a, 0x17, 0x4b, 0x8f, 0x72, 0x34, 0x64, 0xc3, 0xb6, 0x17, 0x21, 0x6e, 0x33, 0x43, 0x9c, 0x93, 0x28, 0x21, 0x84, 0x10, 0x24, 0x38, 0xa1, 0x50, 0x7a, 0x4e, 0x62, 0x92, 0x0c,
0x6a, 0xa5, 0x1a, 0xb3, 0x6c, 0x13, 0x2a, 0xf5, 0x6a, 0x32, 0x94, 0x39, 0x86, 0xa8, 0xfd, 0x99, 0x67, 0x0b, 0xb0, 0xc0, 0x3f, 0x54, 0xd0, 0x3a, 0x5c, 0x2e, 0x3f, 0xcd, 0x53, 0x97, 0x8d, 0xda,
0x80, 0x52, 0xb0, 0x4c, 0x7e, 0x8f, 0x08, 0xe7, 0x0a, 0x20, 0x87, 0x53, 0xae, 0xd4, 0x1b, 0x52, 0x5e, 0x86, 0xb8, 0xcd, 0xa8, 0x97, 0xeb, 0xcc, 0xb2, 0x4d, 0xa8, 0x36, 0x6a, 0xc9, 0x50, 0xf6,
0x21, 0x97, 0x7f, 0x9a, 0x14, 0x88, 0x5f, 0x0e, 0x9d, 0xd1, 0x42, 0x24, 0x6a, 0x2e, 0x5a, 0xa9, 0x04, 0xa2, 0xf6, 0x67, 0x02, 0x4a, 0xc1, 0x2a, 0xf9, 0x3d, 0xc6, 0x9d, 0x6b, 0x80, 0x1c, 0x4e,
0xf2, 0x84, 0xc4, 0x32, 0x73, 0x0a, 0xc8, 0x5f, 0xe5, 0xa2, 0x2b, 0x90, 0xf6, 0x53, 0x1b, 0x87, 0xa5, 0xda, 0x68, 0x4a, 0xc5, 0x7c, 0xe1, 0x45, 0x52, 0x20, 0xb8, 0x1c, 0x3a, 0xa3, 0x85, 0x88,
0xe5, 0xc7, 0xe5, 0xca, 0x3b, 0x65, 0x86, 0x99, 0x11, 0xfc, 0x8a, 0xb4, 0xd7, 0x28, 0xe6, 0x93, 0xd7, 0x5c, 0xb4, 0x72, 0xf5, 0x39, 0xf1, 0x65, 0xf6, 0x0c, 0x90, 0xbf, 0xca, 0x45, 0xd7, 0x20,
0x02, 0xba, 0x06, 0x1b, 0x23, 0xd8, 0x55, 0xa9, 0xf2, 0x77, 0x85, 0xdd, 0x3a, 0x11, 0x09, 0x65, 0xed, 0xa7, 0x36, 0x8f, 0x2a, 0xcf, 0x2a, 0xd5, 0x0f, 0x2a, 0x2c, 0x67, 0xc6, 0xf0, 0xab, 0xd2,
0x8e, 0xe0, 0xd2, 0xc8, 0x72, 0x01, 0xdd, 0x80, 0x6b, 0xa5, 0xa7, 0x5c, 0xb4, 0x22, 0xed, 0xd5, 0x7e, 0xb3, 0x54, 0x48, 0x0a, 0xe8, 0x06, 0x6c, 0x8d, 0x61, 0xd7, 0xa4, 0xea, 0x6f, 0x17, 0xf7,
0x0a, 0x39, 0x69, 0x77, 0xff, 0x71, 0xe1, 0xa9, 0x67, 0xe5, 0x22, 0x5c, 0x19, 0x2d, 0x46, 0x9c, 0x1a, 0x44, 0x24, 0x94, 0x3d, 0x86, 0x2b, 0x63, 0xcb, 0x05, 0x74, 0x0b, 0x6e, 0x94, 0x5f, 0x70,
0x28, 0xe7, 0x4a, 0x85, 0xa4, 0x90, 0xf9, 0xb5, 0x00, 0xf3, 0xee, 0x1a, 0x82, 0xe4, 0x83, 0x09, 0xd1, 0xaa, 0xb4, 0x5f, 0x2f, 0xe6, 0xa5, 0xbd, 0x83, 0x67, 0xc5, 0x17, 0x9e, 0x95, 0x8b, 0x70,
0x96, 0x0a, 0xf5, 0xfd, 0x4a, 0xbe, 0x51, 0x78, 0xfb, 0x30, 0x77, 0x50, 0x4b, 0x5e, 0x40, 0x97, 0x6d, 0xbc, 0x18, 0x01, 0x51, 0xc9, 0x97, 0x8b, 0x49, 0x21, 0xfb, 0x23, 0x01, 0x16, 0xdd, 0x35,
0x21, 0x35, 0xc4, 0xa8, 0xd5, 0x73, 0x52, 0xbd, 0xd6, 0x78, 0xa7, 0x58, 0xdf, 0x4f, 0x0a, 0x04, 0x04, 0x89, 0x07, 0x13, 0x2c, 0x17, 0x1b, 0x07, 0xd5, 0x42, 0xb3, 0xf8, 0xfe, 0x51, 0xfe, 0xb0,
0xcf, 0x43, 0xdc, 0xdd, 0x4a, 0xb9, 0x9e, 0x2b, 0x96, 0x6b, 0xc9, 0x10, 0xd9, 0x1d, 0x23, 0x2c, 0x9e, 0xbc, 0x84, 0xae, 0x42, 0x6a, 0x84, 0x51, 0x6f, 0xe4, 0xa5, 0x46, 0xbd, 0xf9, 0x41, 0xa9,
0x36, 0x8a, 0x7b, 0xe5, 0x8a, 0x54, 0x68, 0xec, 0xe6, 0x08, 0x22, 0xd0, 0x16, 0xbc, 0x14, 0x64, 0x71, 0x90, 0x14, 0x48, 0x3e, 0x8f, 0x70, 0xf7, 0xaa, 0x95, 0x46, 0xbe, 0x54, 0xa9, 0x27, 0x43,
0x7d, 0x48, 0x32, 0x42, 0x16, 0x3f, 0x72, 0xa6, 0x21, 0xb1, 0x99, 0x9d, 0x67, 0x57, 0x21, 0x4e, 0x64, 0x77, 0x8c, 0xb1, 0xd8, 0x2c, 0xed, 0x57, 0xaa, 0x52, 0xb1, 0xb9, 0x97, 0x27, 0x19, 0x81,
0xbe, 0x13, 0x6b, 0xd8, 0x38, 0x55, 0x9b, 0x98, 0x54, 0x82, 0xfb, 0x58, 0xd6, 0xac, 0x93, 0x0f, 0xb6, 0xe1, 0xb5, 0x20, 0xeb, 0x23, 0x92, 0x11, 0xb2, 0xf8, 0xb1, 0x33, 0x8d, 0x88, 0xcd, 0xed,
0xd1, 0x8a, 0xef, 0xe8, 0x2d, 0xb4, 0xbb, 0x56, 0x3f, 0x1d, 0x40, 0x17, 0x93, 0xcf, 0x7e, 0xf5, 0x7e, 0x95, 0x81, 0x38, 0xf9, 0x4e, 0xac, 0x63, 0xe3, 0x4c, 0x6d, 0x61, 0x52, 0x09, 0x1e, 0x60,
0xdb, 0xff, 0x0d, 0x01, 0x8a, 0x66, 0x4f, 0xb8, 0x85, 0x3d, 0x98, 0x91, 0xb0, 0xac, 0xf4, 0xcf, 0x59, 0xb3, 0x4e, 0x3f, 0x45, 0x6b, 0xbe, 0xa3, 0xb7, 0xd8, 0xe9, 0x59, 0x83, 0x74, 0x00, 0x5d,
0x6d, 0x2a, 0x41, 0x4d, 0x45, 0xd1, 0x6c, 0xd6, 0xa0, 0xfa, 0x65, 0x88, 0x3e, 0xe1, 0xff, 0xa0, 0x4c, 0x7e, 0xfe, 0xc3, 0x9f, 0xfc, 0x55, 0x08, 0x50, 0x34, 0x77, 0xca, 0x2d, 0xec, 0xc3, 0x9c,
0x14, 0x68, 0x2b, 0xe8, 0xb6, 0x13, 0x97, 0xa8, 0xb1, 0x38, 0x8a, 0x39, 0xff, 0xe4, 0x84, 0xfe, 0x84, 0x65, 0x65, 0x70, 0x61, 0x53, 0x09, 0x6a, 0x2a, 0x8a, 0xe6, 0x73, 0x06, 0xd5, 0xaf, 0x40,
0x55, 0x80, 0xa5, 0x3d, 0x6c, 0xb1, 0x0e, 0x81, 0xfd, 0x3f, 0x43, 0x81, 0x96, 0x33, 0x53, 0xff, 0xf4, 0x39, 0xff, 0x07, 0xa7, 0x40, 0x5b, 0x41, 0xb7, 0x9d, 0xb8, 0x42, 0x8d, 0xc5, 0x51, 0xcc,
0x13, 0x92, 0x29, 0xbe, 0xf2, 0xec, 0x47, 0xa9, 0x45, 0x58, 0x20, 0x32, 0xb8, 0x63, 0xa9, 0x4d, 0xf9, 0x27, 0x29, 0xf4, 0x47, 0x02, 0xac, 0xec, 0x63, 0x8b, 0x75, 0x08, 0xec, 0xff, 0x39, 0x0a,
0xd9, 0xc2, 0x0a, 0x9d, 0x1f, 0xa1, 0x64, 0xb6, 0x8d, 0xb3, 0x3d, 0x13, 0x1b, 0xf6, 0xff, 0x38, 0xb4, 0x9c, 0x9d, 0xf9, 0x9f, 0x98, 0x4c, 0xf1, 0x8d, 0xcf, 0xff, 0x33, 0xb5, 0x0c, 0x4b, 0x44,
0xa1, 0x36, 0xc4, 0x1c, 0x2f, 0x02, 0x67, 0x17, 0xc7, 0xcf, 0x4e, 0xa6, 0x15, 0x5f, 0x0a, 0x9a, 0x06, 0x77, 0x2d, 0xb5, 0x25, 0x5b, 0x58, 0xa1, 0xf3, 0x23, 0x94, 0xcc, 0x75, 0x70, 0xae, 0x6f,
0x95, 0xac, 0x9a, 0x4e, 0x99, 0x6d, 0x63, 0xf4, 0x2f, 0x02, 0x24, 0x9d, 0xf9, 0xec, 0x86, 0x7f, 0x62, 0xc3, 0xfe, 0x1f, 0x29, 0xd4, 0x81, 0x98, 0x83, 0x22, 0x70, 0x76, 0x71, 0xf2, 0xec, 0x64,
0xd0, 0xb4, 0x13, 0xfe, 0xf3, 0xca, 0xd5, 0x73, 0x16, 0x6f, 0x07, 0xcd, 0x7e, 0x11, 0x2d, 0x39, 0x5a, 0xf1, 0xb5, 0xa0, 0x59, 0xc9, 0xaa, 0xe9, 0x94, 0xb9, 0x0e, 0x46, 0x7f, 0x28, 0x40, 0xd2,
0xb3, 0x67, 0xbb, 0x7c, 0xc2, 0x6f, 0x0a, 0x70, 0x91, 0x3d, 0xe6, 0x0d, 0x3b, 0xb2, 0x33, 0x66, 0x99, 0xcf, 0xfe, 0x87, 0x81, 0xa0, 0x69, 0xa7, 0xfc, 0xe7, 0x96, 0xab, 0x67, 0x2d, 0xde, 0x0d,
0xc2, 0x80, 0x8e, 0x66, 0xfa, 0xc6, 0x54, 0x4e, 0x8a, 0xd9, 0x20, 0x07, 0x57, 0xd2, 0x7e, 0x07, 0x9a, 0xfd, 0x32, 0x5a, 0x71, 0x66, 0xcf, 0xf5, 0xf8, 0x84, 0xff, 0x20, 0xc0, 0x65, 0xf6, 0x98,
0x1f, 0x08, 0x19, 0xf4, 0x4f, 0x90, 0x70, 0x02, 0xc5, 0x7a, 0x87, 0x41, 0x61, 0x9a, 0xf0, 0x89, 0x37, 0x0a, 0x64, 0x77, 0xc2, 0x84, 0x01, 0x1d, 0xd1, 0xf4, 0xad, 0x99, 0x40, 0x8a, 0xb9, 0x20,
0xeb, 0x34, 0xe0, 0xc4, 0x4c, 0x90, 0x0f, 0x4b, 0x68, 0x71, 0xe0, 0x03, 0x6b, 0xc3, 0x7d, 0x4d, 0x80, 0x6b, 0x69, 0x3f, 0xc0, 0xc7, 0x42, 0x16, 0x7d, 0x29, 0x40, 0x92, 0x95, 0x89, 0x0c, 0x23,
0x80, 0x25, 0x56, 0xa5, 0xba, 0x5d, 0x78, 0x75, 0x9a, 0x00, 0xb9, 0x5b, 0x4d, 0xe9, 0xeb, 0x53, 0xfd, 0x38, 0xcb, 0x4d, 0x2b, 0x4a, 0x3d, 0x4d, 0xca, 0xc0, 0xec, 0xbe, 0x1f, 0x04, 0x67, 0x3d,
0x38, 0x27, 0xde, 0x09, 0x72, 0x6c, 0x39, 0xed, 0x75, 0x8c, 0x84, 0xe6, 0xff, 0x05, 0x58, 0xf2, 0x8d, 0x86, 0x70, 0xc8, 0x0f, 0x52, 0xbe, 0x13, 0x3c, 0xbf, 0x0f, 0x09, 0x27, 0x70, 0xac, 0x97,
0xf5, 0xd7, 0xc6, 0x25, 0x2f, 0xa8, 0x19, 0x17, 0xb8, 0xf9, 0xdf, 0x08, 0x72, 0xe8, 0xb2, 0xb8, 0x19, 0x14, 0xb6, 0x29, 0x9f, 0xdc, 0x4e, 0x43, 0x50, 0xcc, 0x06, 0x81, 0x58, 0x41, 0xcb, 0x43,
0xea, 0x71, 0x28, 0xcb, 0xba, 0x3d, 0x7d, 0xe2, 0xd8, 0xa7, 0x02, 0x6c, 0x48, 0xd8, 0xc4, 0x1d, 0x10, 0xac, 0x2d, 0xf8, 0xb7, 0x02, 0xac, 0xb8, 0xdd, 0xc1, 0x20, 0xdc, 0x9f, 0x25, 0x60, 0xee,
0xa5, 0xd4, 0x77, 0xf5, 0x2a, 0x9b, 0xb4, 0xc0, 0x2c, 0x8d, 0xcb, 0x61, 0x90, 0x23, 0xb9, 0x20, 0xd6, 0x57, 0xfa, 0xe6, 0x0c, 0xe0, 0xc4, 0x7b, 0x41, 0xc0, 0x56, 0xd3, 0x5e, 0x60, 0xc4, 0x35,
0x47, 0xb6, 0xc4, 0xeb, 0x3e, 0x47, 0x0c, 0x3a, 0xf5, 0xa9, 0x6b, 0x4e, 0x2f, 0x90, 0x58, 0x3b, 0x7f, 0x23, 0xc0, 0x8a, 0xaf, 0xdf, 0x37, 0x29, 0x99, 0x82, 0x9a, 0x83, 0x81, 0xe1, 0x7a, 0x3b,
0xef, 0x39, 0x81, 0xe4, 0x74, 0xc4, 0xa6, 0x04, 0x12, 0xeb, 0x8b, 0x79, 0x81, 0xc4, 0x5c, 0x98, 0x08, 0xd0, 0x55, 0x71, 0xdd, 0x03, 0x28, 0xc7, 0xba, 0x4f, 0x03, 0x02, 0xec, 0x2b, 0x01, 0xb6,
0x0a, 0x48, 0xee, 0x26, 0xd2, 0x24, 0x20, 0x51, 0xd9, 0x29, 0x81, 0x44, 0x1d, 0x23, 0xa1, 0xd1, 0x24, 0x6c, 0xe2, 0xae, 0x52, 0x1e, 0xb8, 0x7a, 0xa7, 0x2d, 0x5a, 0xf0, 0x96, 0x27, 0xc5, 0x30,
0x61, 0x49, 0xc2, 0x6d, 0xfd, 0x14, 0x4f, 0x13, 0x9d, 0xa0, 0x14, 0x05, 0x07, 0x23, 0xe3, 0x0b, 0x08, 0x48, 0x3e, 0x08, 0xc8, 0xb6, 0x78, 0xd3, 0x07, 0xc4, 0xa0, 0x53, 0x9f, 0xb9, 0xe6, 0xf4,
0xc6, 0xff, 0x79, 0x90, 0x3b, 0x31, 0x18, 0xa3, 0x3b, 0x6a, 0x2f, 0x88, 0x5b, 0xea, 0x4b, 0x10, 0x26, 0x12, 0x6b, 0x2f, 0xbe, 0x64, 0x22, 0x39, 0x1d, 0xba, 0x19, 0x13, 0x89, 0xf5, 0xe9, 0xbc,
0x6e, 0x5d, 0x9d, 0x4a, 0x86, 0x21, 0xd6, 0xd7, 0xf9, 0x5c, 0x70, 0xcb, 0x1d, 0x19, 0x8d, 0xdb, 0x89, 0xc4, 0x20, 0xcc, 0x94, 0x48, 0xee, 0xa6, 0xd6, 0xb4, 0x44, 0xa2, 0xb2, 0x33, 0x26, 0x12,
0xa1, 0xab, 0xc2, 0x6e, 0x10, 0x3d, 0xe7, 0x55, 0xe1, 0xea, 0x84, 0x4d, 0x79, 0x55, 0xf0, 0x8e, 0x05, 0x46, 0x5c, 0xa3, 0xc3, 0x8a, 0x84, 0x3b, 0xfa, 0x19, 0x9e, 0xc5, 0x3b, 0x41, 0x21, 0x0a,
0x09, 0xfa, 0xc4, 0xed, 0x85, 0xfd, 0x58, 0xb0, 0x35, 0xe9, 0x6d, 0xc0, 0x7e, 0xb2, 0x48, 0x5f, 0x76, 0x46, 0xd6, 0xe7, 0x8c, 0xbf, 0xf6, 0x64, 0xee, 0x54, 0x67, 0x8c, 0xef, 0xf0, 0xbd, 0x62,
0x9b, 0x28, 0x39, 0xa5, 0x3f, 0xf6, 0x5b, 0x83, 0xf7, 0xea, 0xb2, 0x03, 0x33, 0xd5, 0xd5, 0x35, 0xde, 0x52, 0x2c, 0x41, 0x79, 0xeb, 0xea, 0x9c, 0xb2, 0x1c, 0x62, 0x7d, 0xa6, 0x6f, 0x24, 0x6f,
0xdc, 0xb6, 0x9a, 0x74, 0x75, 0xd9, 0x5d, 0xa1, 0xe9, 0xae, 0x2e, 0x1e, 0x30, 0x92, 0xb9, 0x53, 0x39, 0x90, 0xf1, 0x79, 0x3b, 0x72, 0x75, 0xd9, 0x0d, 0xab, 0x97, 0xbc, 0xba, 0x5c, 0x9d, 0xb9,
0x5e, 0x53, 0x94, 0x8e, 0xe5, 0xe0, 0x8c, 0xbd, 0x3c, 0x55, 0x8f, 0xc5, 0x14, 0x6f, 0x05, 0xcd, 0x19, 0xaf, 0x2e, 0xde, 0xc1, 0xa1, 0xd7, 0x82, 0x83, 0xc2, 0x7e, 0xbc, 0xd8, 0x9e, 0x76, 0x2d,
0x9e, 0x44, 0x89, 0xc1, 0xec, 0x6d, 0x32, 0xd5, 0x7f, 0x0b, 0x90, 0xb4, 0x8f, 0x1a, 0xa7, 0x77, 0xd8, 0x4f, 0x28, 0xe9, 0x1b, 0x53, 0x25, 0x67, 0xc4, 0x63, 0xbf, 0x7d, 0x78, 0xaf, 0x52, 0xdb,
0x34, 0x26, 0x57, 0xc3, 0x3d, 0xa9, 0x40, 0x2c, 0xdf, 0x0f, 0xf2, 0x60, 0x33, 0xbd, 0xee, 0xc2, 0x31, 0x33, 0x5d, 0xa5, 0xa3, 0x6d, 0xb4, 0x69, 0x57, 0xa9, 0xdd, 0xa5, 0x9a, 0xed, 0x2a, 0xe5,
0x32, 0x37, 0x66, 0x66, 0xf9, 0x7f, 0xef, 0x92, 0x48, 0x7c, 0x47, 0x80, 0x0d, 0x1a, 0x8a, 0xc0, 0x0e, 0x23, 0x91, 0x3b, 0xe3, 0x35, 0x4e, 0xf9, 0x44, 0x0e, 0x8e, 0xd8, 0xeb, 0x33, 0xf5, 0x7c,
0x47, 0x8e, 0xa0, 0xf0, 0xec, 0x4c, 0xe1, 0xb6, 0xc7, 0xd6, 0x18, 0x47, 0xd1, 0x95, 0x6c, 0x97, 0x4c, 0xf1, 0x4e, 0xd0, 0xec, 0x49, 0x94, 0x18, 0xce, 0xde, 0x21, 0x53, 0xfd, 0x85, 0xeb, 0x0a,
0xc8, 0xa8, 0xd8, 0x74, 0x39, 0xda, 0x74, 0x0c, 0xa0, 0x8f, 0x20, 0x96, 0x53, 0x94, 0xd2, 0xb1, 0x77, 0x7a, 0x59, 0x13, 0x62, 0x35, 0xda, 0x23, 0x0b, 0xcc, 0xe5, 0x47, 0x41, 0x08, 0x32, 0xe9,
0x5c, 0xa9, 0x57, 0x03, 0x7d, 0xda, 0x1a, 0xdb, 0xcc, 0x72, 0x35, 0xa0, 0xc6, 0x40, 0x46, 0x5c, 0x4d, 0x57, 0x2e, 0x73, 0x63, 0x66, 0x8e, 0xff, 0x37, 0x32, 0xf1, 0xc4, 0x3f, 0x0b, 0xb0, 0x45,
0x1a, 0x4a, 0x5a, 0x56, 0xb7, 0xba, 0x24, 0x50, 0x1f, 0x0b, 0xee, 0xa6, 0x5d, 0xbd, 0x8a, 0x5e, 0x5d, 0x11, 0xf8, 0xe8, 0x12, 0xe4, 0x9e, 0xdd, 0x19, 0x60, 0x7b, 0x6c, 0x4d, 0x00, 0x8a, 0xae,
0x9e, 0x78, 0x9b, 0xd3, 0x19, 0x03, 0x93, 0xf6, 0x37, 0x41, 0x1e, 0x5c, 0x49, 0xaf, 0xf9, 0x3c, 0xe5, 0x7a, 0x44, 0x46, 0xc5, 0xa6, 0x0b, 0x68, 0xcb, 0x31, 0x80, 0x3e, 0x83, 0x58, 0x5e, 0x51,
0x70, 0x9f, 0x85, 0x1a, 0xcc, 0xf3, 0x3b, 0x61, 0x7c, 0x30, 0x82, 0x26, 0x0e, 0xde, 0xce, 0x19, 0xca, 0x27, 0x72, 0xb5, 0x51, 0x0b, 0xc4, 0xb4, 0x3d, 0xb1, 0xb9, 0xe6, 0x6a, 0x88, 0x4d, 0x48,
0xff, 0xd2, 0xd1, 0xf7, 0x05, 0x58, 0xe2, 0x1f, 0x75, 0x7d, 0xe7, 0x23, 0x73, 0xec, 0xed, 0x38, 0x19, 0x71, 0x65, 0x24, 0x68, 0x39, 0xdd, 0xea, 0x11, 0x47, 0x7d, 0x21, 0xb8, 0x9b, 0x88, 0x8d,
0xb2, 0x0b, 0x96, 0xbe, 0x7b, 0x0e, 0x0d, 0x9e, 0xa3, 0xd7, 0x83, 0x1c, 0x5d, 0x17, 0x57, 0xa8, 0x1a, 0x7a, 0x7d, 0xea, 0x6d, 0x4e, 0x67, 0x0c, 0x0c, 0xda, 0x6f, 0x05, 0x21, 0xb8, 0x96, 0xde,
0xa3, 0x2d, 0xa2, 0x44, 0xbd, 0x6d, 0x98, 0x54, 0x95, 0x84, 0xe7, 0xa7, 0x02, 0x5c, 0xb4, 0x1d, 0xf0, 0x21, 0x70, 0x9f, 0x85, 0x1a, 0x2c, 0xf2, 0x3b, 0x61, 0xb2, 0x33, 0x82, 0x26, 0x0e, 0xde,
0x1e, 0x7c, 0xf0, 0x9a, 0xe8, 0xb5, 0xf3, 0x3c, 0xa4, 0xdb, 0x5e, 0xbf, 0x7e, 0x3e, 0x25, 0xee, 0xce, 0x59, 0xff, 0xd2, 0xd1, 0xbf, 0x09, 0xb0, 0xc2, 0x3f, 0x32, 0x07, 0xce, 0x47, 0xef, 0xc4,
0x78, 0x30, 0xcc, 0xc5, 0xf5, 0x6c, 0x4b, 0xd3, 0x8f, 0x64, 0x8d, 0x14, 0xd2, 0x44, 0x59, 0x37, 0xdb, 0x71, 0x6c, 0x57, 0x2e, 0xfd, 0xe0, 0x02, 0x1a, 0x3c, 0x46, 0x6f, 0x05, 0x01, 0xdd, 0x14,
0x5a, 0xa6, 0xdb, 0xfb, 0xff, 0x12, 0x60, 0x95, 0xee, 0xc7, 0x77, 0xd9, 0x94, 0xee, 0x17, 0xe9, 0xd7, 0x28, 0xd0, 0x36, 0x51, 0xa2, 0x68, 0x9b, 0x26, 0x55, 0x25, 0xee, 0xf9, 0x1f, 0x01, 0x2e,
0xe7, 0xa8, 0x8a, 0x86, 0x9e, 0xb4, 0xc5, 0x9d, 0x20, 0xbf, 0xd6, 0xd0, 0x6a, 0xd6, 0xf5, 0xb2, 0xdb, 0x80, 0x87, 0x1f, 0xe0, 0x26, 0x7a, 0xf3, 0x22, 0x0f, 0xfb, 0x36, 0xea, 0xb7, 0x2e, 0xa6,
0x9d, 0xe5, 0xa6, 0xc8, 0xf7, 0xd0, 0xbf, 0xd9, 0x0e, 0xf1, 0xd5, 0xfe, 0x59, 0x1d, 0x1a, 0x5b, 0xc4, 0x81, 0x07, 0xa7, 0xb9, 0xb8, 0x99, 0x6b, 0x6b, 0xfa, 0xb1, 0xac, 0x91, 0xc2, 0x9e, 0x28,
0xa6, 0xb9, 0x1d, 0x6a, 0xe3, 0x87, 0x3f, 0x14, 0x3e, 0xcd, 0xfd, 0xbb, 0x80, 0xde, 0x84, 0x28, 0xeb, 0x46, 0xdb, 0x74, 0xa3, 0xff, 0x73, 0x01, 0xd6, 0xe9, 0x7e, 0xfc, 0x90, 0x4d, 0xe9, 0x7e,
0xf9, 0x14, 0xdf, 0xcc, 0x55, 0x8b, 0x62, 0x06, 0x6d, 0x9d, 0x58, 0x56, 0xd7, 0x7c, 0x90, 0xcd, 0x21, 0x7f, 0x89, 0xaa, 0x68, 0xe4, 0x89, 0x5d, 0xdc, 0x0d, 0xc2, 0xb5, 0x81, 0xd6, 0x73, 0xae,
0xb6, 0x54, 0xeb, 0xa4, 0x77, 0xb4, 0xdd, 0xd4, 0xdb, 0x59, 0x32, 0xb7, 0xb3, 0x82, 0xee, 0xfb, 0x97, 0xf6, 0x1c, 0x37, 0x45, 0xbe, 0xcf, 0xfe, 0xd8, 0x06, 0xc4, 0x57, 0xfb, 0x2b, 0x05, 0x34,
0xad, 0x2c, 0x31, 0xbf, 0x13, 0x7e, 0x75, 0xfb, 0x6e, 0x46, 0x08, 0xed, 0x24, 0xe5, 0x6e, 0x57, 0xb1, 0x4c, 0x73, 0x03, 0xea, 0xe0, 0x27, 0xff, 0x21, 0x7c, 0x95, 0xff, 0x13, 0x01, 0xbd, 0x03,
0xe3, 0x97, 0x78, 0xf6, 0x3d, 0x53, 0xef, 0x0c, 0x53, 0x5a, 0x46, 0xb7, 0xf9, 0xc0, 0x27, 0xf3, 0xd1, 0x7c, 0xdf, 0x3a, 0xcd, 0xe4, 0x6b, 0x25, 0x31, 0x8b, 0xb6, 0x4f, 0x2d, 0xab, 0x67, 0x3e,
0xc0, 0x27, 0xf3, 0xee, 0x8d, 0x71, 0x33, 0x12, 0x09, 0x3a, 0xed, 0xd1, 0x2c, 0x0d, 0xcd, 0x6b, 0xce, 0xe5, 0xda, 0xaa, 0x75, 0xda, 0x3f, 0xde, 0x69, 0xe9, 0x9d, 0x1c, 0x99, 0xdb, 0x59, 0x41,
0x7f, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x86, 0x9f, 0x6d, 0x7d, 0xe5, 0x34, 0x00, 0x00, 0xef, 0xe3, 0x76, 0x8e, 0x98, 0xdf, 0x0d, 0xdf, 0xdf, 0x79, 0x90, 0x15, 0x42, 0xbb, 0x49, 0xb9,
0xd7, 0xd3, 0xf8, 0x25, 0x9e, 0xfb, 0xc8, 0xd4, 0xbb, 0xa3, 0x94, 0xb6, 0xd1, 0x6b, 0x3d, 0xf6,
0xc9, 0x3c, 0xf6, 0xc9, 0x7c, 0x78, 0x6b, 0xd2, 0x8c, 0x44, 0x82, 0x4e, 0x7b, 0x3c, 0x4f, 0x5d,
0xf3, 0xe6, 0x2f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x14, 0xb2, 0x4a, 0xb5, 0x35, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
var _ context.Context var _ context.Context
var _ grpc.ClientConn var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file // This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against. // is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4 const _ = grpc.SupportPackageIsVersion6
// AuthServiceClient is the client API for AuthService service. // AuthServiceClient is the client API for AuthService service.
// //
@ -3323,6 +3366,7 @@ type AuthServiceClient interface {
GetMyUser(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserView, error) GetMyUser(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserView, error)
GetMyUserProfile(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserProfileView, error) GetMyUserProfile(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserProfileView, error)
UpdateMyUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UserProfile, error) UpdateMyUserProfile(ctx context.Context, in *UpdateUserProfileRequest, opts ...grpc.CallOption) (*UserProfile, error)
ChangeMyUserName(ctx context.Context, in *ChangeUserNameRequest, opts ...grpc.CallOption) (*empty.Empty, error)
GetMyUserEmail(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserEmailView, error) GetMyUserEmail(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserEmailView, error)
ChangeMyUserEmail(ctx context.Context, in *UpdateUserEmailRequest, opts ...grpc.CallOption) (*UserEmail, error) ChangeMyUserEmail(ctx context.Context, in *UpdateUserEmailRequest, opts ...grpc.CallOption) (*UserEmail, error)
VerifyMyUserEmail(ctx context.Context, in *VerifyMyUserEmailRequest, opts ...grpc.CallOption) (*empty.Empty, error) VerifyMyUserEmail(ctx context.Context, in *VerifyMyUserEmailRequest, opts ...grpc.CallOption) (*empty.Empty, error)
@ -3351,10 +3395,10 @@ type AuthServiceClient interface {
} }
type authServiceClient struct { type authServiceClient struct {
cc *grpc.ClientConn cc grpc.ClientConnInterface
} }
func NewAuthServiceClient(cc *grpc.ClientConn) AuthServiceClient { func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
return &authServiceClient{cc} return &authServiceClient{cc}
} }
@ -3421,6 +3465,15 @@ func (c *authServiceClient) UpdateMyUserProfile(ctx context.Context, in *UpdateU
return out, nil return out, nil
} }
func (c *authServiceClient) ChangeMyUserName(ctx context.Context, in *ChangeUserNameRequest, opts ...grpc.CallOption) (*empty.Empty, error) {
out := new(empty.Empty)
err := c.cc.Invoke(ctx, "/caos.zitadel.auth.api.v1.AuthService/ChangeMyUserName", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authServiceClient) GetMyUserEmail(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserEmailView, error) { func (c *authServiceClient) GetMyUserEmail(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserEmailView, error) {
out := new(UserEmailView) out := new(UserEmailView)
err := c.cc.Invoke(ctx, "/caos.zitadel.auth.api.v1.AuthService/GetMyUserEmail", in, out, opts...) err := c.cc.Invoke(ctx, "/caos.zitadel.auth.api.v1.AuthService/GetMyUserEmail", in, out, opts...)
@ -3631,6 +3684,7 @@ type AuthServiceServer interface {
GetMyUser(context.Context, *empty.Empty) (*UserView, error) GetMyUser(context.Context, *empty.Empty) (*UserView, error)
GetMyUserProfile(context.Context, *empty.Empty) (*UserProfileView, error) GetMyUserProfile(context.Context, *empty.Empty) (*UserProfileView, error)
UpdateMyUserProfile(context.Context, *UpdateUserProfileRequest) (*UserProfile, error) UpdateMyUserProfile(context.Context, *UpdateUserProfileRequest) (*UserProfile, error)
ChangeMyUserName(context.Context, *ChangeUserNameRequest) (*empty.Empty, error)
GetMyUserEmail(context.Context, *empty.Empty) (*UserEmailView, error) GetMyUserEmail(context.Context, *empty.Empty) (*UserEmailView, error)
ChangeMyUserEmail(context.Context, *UpdateUserEmailRequest) (*UserEmail, error) ChangeMyUserEmail(context.Context, *UpdateUserEmailRequest) (*UserEmail, error)
VerifyMyUserEmail(context.Context, *VerifyMyUserEmailRequest) (*empty.Empty, error) VerifyMyUserEmail(context.Context, *VerifyMyUserEmailRequest) (*empty.Empty, error)
@ -3683,6 +3737,9 @@ func (*UnimplementedAuthServiceServer) GetMyUserProfile(ctx context.Context, req
func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(ctx context.Context, req *UpdateUserProfileRequest) (*UserProfile, error) { func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(ctx context.Context, req *UpdateUserProfileRequest) (*UserProfile, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserProfile not implemented") return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserProfile not implemented")
} }
func (*UnimplementedAuthServiceServer) ChangeMyUserName(ctx context.Context, req *ChangeUserNameRequest) (*empty.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method ChangeMyUserName not implemented")
}
func (*UnimplementedAuthServiceServer) GetMyUserEmail(ctx context.Context, req *empty.Empty) (*UserEmailView, error) { func (*UnimplementedAuthServiceServer) GetMyUserEmail(ctx context.Context, req *empty.Empty) (*UserEmailView, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetMyUserEmail not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetMyUserEmail not implemented")
} }
@ -3880,6 +3937,24 @@ func _AuthService_UpdateMyUserProfile_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _AuthService_ChangeMyUserName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ChangeUserNameRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthServiceServer).ChangeMyUserName(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/caos.zitadel.auth.api.v1.AuthService/ChangeMyUserName",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthServiceServer).ChangeMyUserName(ctx, req.(*ChangeUserNameRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthService_GetMyUserEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _AuthService_GetMyUserEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(empty.Empty) in := new(empty.Empty)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -4308,6 +4383,10 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{
MethodName: "UpdateMyUserProfile", MethodName: "UpdateMyUserProfile",
Handler: _AuthService_UpdateMyUserProfile_Handler, Handler: _AuthService_UpdateMyUserProfile_Handler,
}, },
{
MethodName: "ChangeMyUserName",
Handler: _AuthService_ChangeMyUserName_Handler,
},
{ {
MethodName: "GetMyUserEmail", MethodName: "GetMyUserEmail",
Handler: _AuthService_GetMyUserEmail_Handler, Handler: _AuthService_GetMyUserEmail_Handler,

File diff suppressed because it is too large Load Diff

View File

@ -614,6 +614,32 @@
] ]
} }
}, },
"/users/me/username": {
"put": {
"operationId": "ChangeMyUserName",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1ChangeUserNameRequest"
}
}
],
"tags": [
"AuthService"
]
}
},
"/validate": { "/validate": {
"get": { "get": {
"operationId": "Validate", "operationId": "Validate",
@ -665,6 +691,14 @@
} }
} }
}, },
"v1ChangeUserNameRequest": {
"type": "object",
"properties": {
"user_name": {
"type": "string"
}
}
},
"v1Changes": { "v1Changes": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -97,6 +97,26 @@ func (mr *MockAuthServiceClientMockRecorder) ChangeMyUserEmail(arg0, arg1 interf
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeMyUserEmail", reflect.TypeOf((*MockAuthServiceClient)(nil).ChangeMyUserEmail), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeMyUserEmail", reflect.TypeOf((*MockAuthServiceClient)(nil).ChangeMyUserEmail), varargs...)
} }
// ChangeMyUserName mocks base method
func (m *MockAuthServiceClient) ChangeMyUserName(arg0 context.Context, arg1 *auth.ChangeUserNameRequest, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ChangeMyUserName", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChangeMyUserName indicates an expected call of ChangeMyUserName
func (mr *MockAuthServiceClientMockRecorder) ChangeMyUserName(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeMyUserName", reflect.TypeOf((*MockAuthServiceClient)(nil).ChangeMyUserName), varargs...)
}
// ChangeMyUserPhone mocks base method // ChangeMyUserPhone mocks base method
func (m *MockAuthServiceClient) ChangeMyUserPhone(arg0 context.Context, arg1 *auth.UpdateUserPhoneRequest, arg2 ...grpc.CallOption) (*auth.UserPhone, error) { func (m *MockAuthServiceClient) ChangeMyUserPhone(arg0 context.Context, arg1 *auth.UpdateUserPhoneRequest, arg2 ...grpc.CallOption) (*auth.UserPhone, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -94,6 +94,17 @@ service AuthService {
}; };
} }
rpc ChangeMyUserName(ChangeUserNameRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
put: "/users/me/username"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "authenticated"
};
}
rpc GetMyUserEmail(google.protobuf.Empty) returns (UserEmailView) { rpc GetMyUserEmail(google.protobuf.Empty) returns (UserEmailView) {
option (google.api.http) = { option (google.api.http) = {
get: "/users/me/email" get: "/users/me/email"
@ -437,6 +448,10 @@ message UpdateUserProfileRequest {
Gender gender = 5; Gender gender = 5;
} }
message ChangeUserNameRequest {
string user_name = 1 [(validate.rules).string = {max_len: 200}];
}
message UserEmail { message UserEmail {
string id = 1; string id = 1;
string email = 2; string email = 2;

View File

@ -24,8 +24,8 @@ var ManagementService_AuthMethods = authz.MethodMapping{
CheckParam: "", CheckParam: "",
}, },
"/caos.zitadel.management.api.v1.ManagementService/GetUserByEmailGlobal": authz.Option{ "/caos.zitadel.management.api.v1.ManagementService/GetUserByLoginNameGlobal": authz.Option{
Permission: "user.read", Permission: "user.global.read",
CheckParam: "", CheckParam: "",
}, },
@ -104,6 +104,11 @@ var ManagementService_AuthMethods = authz.MethodMapping{
CheckParam: "", CheckParam: "",
}, },
"/caos.zitadel.management.api.v1.ManagementService/ChangeUserUserName": authz.Option{
Permission: "user.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/ChangeUserEmail": authz.Option{ "/caos.zitadel.management.api.v1.ManagementService/ChangeUserEmail": authz.Option{
Permission: "user.write", Permission: "user.write",
CheckParam: "", CheckParam: "",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -357,6 +357,26 @@ func (mr *MockManagementServiceClientMockRecorder) ChangeUserPhone(arg0, arg1 in
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeUserPhone", reflect.TypeOf((*MockManagementServiceClient)(nil).ChangeUserPhone), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeUserPhone", reflect.TypeOf((*MockManagementServiceClient)(nil).ChangeUserPhone), varargs...)
} }
// ChangeUserUserName mocks base method
func (m *MockManagementServiceClient) ChangeUserUserName(arg0 context.Context, arg1 *management.UpdateUserUserNameRequest, arg2 ...grpc.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ChangeUserUserName", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChangeUserUserName indicates an expected call of ChangeUserUserName
func (mr *MockManagementServiceClientMockRecorder) ChangeUserUserName(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeUserUserName", reflect.TypeOf((*MockManagementServiceClient)(nil).ChangeUserUserName), varargs...)
}
// CreateLoginPolicy mocks base method // CreateLoginPolicy mocks base method
func (m *MockManagementServiceClient) CreateLoginPolicy(arg0 context.Context, arg1 *management.LoginPolicyAdd, arg2 ...grpc.CallOption) (*management.LoginPolicy, error) { func (m *MockManagementServiceClient) CreateLoginPolicy(arg0 context.Context, arg1 *management.LoginPolicyAdd, arg2 ...grpc.CallOption) (*management.LoginPolicy, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -1117,26 +1137,6 @@ func (mr *MockManagementServiceClientMockRecorder) GetUserAddress(arg0, arg1 int
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserAddress", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserAddress), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserAddress", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserAddress), varargs...)
} }
// GetUserByEmailGlobal mocks base method
func (m *MockManagementServiceClient) GetUserByEmailGlobal(arg0 context.Context, arg1 *management.Email, arg2 ...grpc.CallOption) (*management.UserView, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetUserByEmailGlobal", varargs...)
ret0, _ := ret[0].(*management.UserView)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserByEmailGlobal indicates an expected call of GetUserByEmailGlobal
func (mr *MockManagementServiceClientMockRecorder) GetUserByEmailGlobal(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByEmailGlobal", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserByEmailGlobal), varargs...)
}
// GetUserByID mocks base method // GetUserByID mocks base method
func (m *MockManagementServiceClient) GetUserByID(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserView, error) { func (m *MockManagementServiceClient) GetUserByID(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserView, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -1157,6 +1157,26 @@ func (mr *MockManagementServiceClientMockRecorder) GetUserByID(arg0, arg1 interf
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserByID), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserByID), varargs...)
} }
// GetUserByLoginNameGlobal mocks base method
func (m *MockManagementServiceClient) GetUserByLoginNameGlobal(arg0 context.Context, arg1 *management.LoginName, arg2 ...grpc.CallOption) (*management.UserView, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetUserByLoginNameGlobal", varargs...)
ret0, _ := ret[0].(*management.UserView)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserByLoginNameGlobal indicates an expected call of GetUserByLoginNameGlobal
func (mr *MockManagementServiceClientMockRecorder) GetUserByLoginNameGlobal(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByLoginNameGlobal", reflect.TypeOf((*MockManagementServiceClient)(nil).GetUserByLoginNameGlobal), varargs...)
}
// GetUserEmail mocks base method // GetUserEmail mocks base method
func (m *MockManagementServiceClient) GetUserEmail(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserEmailView, error) { func (m *MockManagementServiceClient) GetUserEmail(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserEmailView, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -81,14 +81,14 @@ service ManagementService {
}; };
} }
// GetUserByEmailGlobal returns User, global search is overall organisations // GetUserByLoginNameGlobal returns User, global search is overall organisations
rpc GetUserByEmailGlobal(Email) returns (UserView) { rpc GetUserByLoginNameGlobal(LoginName) returns (UserView) {
option (google.api.http) = { option (google.api.http) = {
get: "/global/users/_byemail" get: "/global/users/_byloginname"
}; };
option (caos.zitadel.utils.v1.auth_option) = { option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.read" permission: "user.global.read"
}; };
} }
@ -254,6 +254,16 @@ service ManagementService {
}; };
} }
rpc ChangeUserUserName(UpdateUserUserNameRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
get: "/users/{id}/username"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.write"
};
}
rpc ChangeUserEmail(UpdateUserEmailRequest) returns (UserEmail) { rpc ChangeUserEmail(UpdateUserEmailRequest) returns (UserEmail) {
option (google.api.http) = { option (google.api.http) = {
put: "/users/{id}/email" put: "/users/{id}/email"
@ -1459,8 +1469,8 @@ message UserID {
string id = 1; string id = 1;
} }
message Email { message LoginName {
string email = 1; string login_name = 1;
} }
message UniqueUserRequest { message UniqueUserRequest {
@ -1648,6 +1658,11 @@ message UpdateUserProfileRequest {
Gender gender = 6; Gender gender = 6;
} }
message UpdateUserUserNameRequest {
string id = 1;
string user_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
}
message UserEmail { message UserEmail {
string id = 1; string id = 1;
string email = 2; string email = 2;