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

View File

@ -89,6 +89,7 @@ SystemDefaults:
InitCode: '$ZITADEL_ACCOUNTS/user/init?userID={{.UserID}}&code={{.Code}}&passwordset={{.PasswordSet}}'
PasswordReset: '$ZITADEL_ACCOUNTS/password/init?userID={{.UserID}}&code={{.Code}}'
VerifyEmail: '$ZITADEL_ACCOUNTS/mail/verification?userID={{.UserID}}&code={{.Code}}'
DomainClaimed: '$ZITADEL_ACCOUNTS/login'
Providers:
Chat:
Url: $CHAT_URL
@ -133,4 +134,11 @@ SystemDefaults:
Subject: 'VerifyPhone.Subject'
Greeting: 'VerifyPhone.Greeting'
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 { 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 { ProjectService } from 'src/app/services/project.service';
import { ToastService } from 'src/app/services/toast.service';
@ -21,7 +21,7 @@ export enum CreationType {
export class MemberCreateDialogComponent {
private projectId: string = '';
private grantId: string = '';
public preselectedUsers: Array<User.AsObject> = [];
public preselectedUsers: Array<UserView.AsObject> = [];
public creationType!: CreationType;
@ -31,7 +31,7 @@ export class MemberCreateDialogComponent {
CreationType.PROJECT_OWNED,
CreationType.PROJECT_GRANTED,
];
public users: Array<User.AsObject> = [];
public users: Array<UserView.AsObject> = [];
public roles: Array<ProjectRole.AsObject> | string[] = [];
public CreationType: any = CreationType;
public ProjectAutocompleteType: any = ProjectAutocompleteType;

View File

@ -6,7 +6,7 @@ import { MatSelectChange } from '@angular/material/select';
import { MatTable } from '@angular/material/table';
import { ActivatedRoute } from '@angular/router';
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 { ToastService } from 'src/app/services/toast.service';
@ -128,7 +128,7 @@ export class ProjectMembersComponent {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
const users: User.AsObject[] = resp.users;
const users: UserView.AsObject[] = resp.users;
const roles: string[] = resp.roles;
if (users && users.length && roles && roles.length) {

View File

@ -1,17 +1,17 @@
<form>
<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" />
<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"
(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-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"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)" />
@ -23,15 +23,15 @@
</mat-option>
<mat-option *ngFor="let user of filteredUsers" [value]="user">
{{user.firstName}} {{user.lastName}}
<small>{{user.email}}</small>
<small>{{user.preferredLoginName}}</small>
</mat-option>
</mat-autocomplete>
</mat-form-field>
<div *ngIf="target == UserTarget.EXTERNAL" class="line">
<mat-form-field class="form-field" appearance="outline">
<mat-label>Global User Email</mat-label>
<input matInput type="text" [formControl]="globalEmailControl" />
<mat-label>Global User Loginname</mat-label>
<input matInput type="text" [formControl]="globalLoginNameControl" />
</mat-form-field>
<button color="primary" mat-icon-button (click)="getGlobalUser()">
@ -42,7 +42,7 @@
<div *ngIf="target == UserTarget.EXTERNAL && users.length > 0">
<span class="found-label">{{'USER.SEARCH.FOUND' | translate}}:</span>
<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>
<i class="las la-minus-circle" (click)="users.splice(i, 1)"></i>
</button>
@ -52,4 +52,4 @@
<p class="target-desc">{{(target == UserTarget.SELF ? 'USER.TARGET.SELF' : 'USER.TARGET.EXTERNAL') | translate}}
<a (click)="changeTarget()">{{'USER.TARGET.CLICKHERE' | translate}}</a>
</p>
</form>
</form>

View File

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

View File

@ -22,7 +22,7 @@ import {
ProjectState,
ProjectType,
ProjectView,
User,
UserView,
UserGrantSearchKey,
} from 'src/app/proto/generated/management_pb';
import { OrgService } from 'src/app/services/org.service';
@ -216,7 +216,7 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
dialogRef.afterClosed().subscribe(resp => {
if (resp) {
const users: User.AsObject[] = resp.users;
const users: UserView.AsObject[] = resp.users;
const roles: string[] = resp.roles;
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 { Router } from '@angular/router';
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 { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { OrgService } from 'src/app/services/org.service';
@ -35,7 +35,7 @@ export class MembershipsComponent implements OnInit {
public loading: boolean = false;
public memberships!: UserMembershipSearchResponse.AsObject;
@Input() public user!: User.AsObject;
@Input() public user!: UserView.AsObject;
public MemberType: any = MemberType;
constructor(
@ -92,7 +92,7 @@ export class MembershipsComponent implements OnInit {
}
public createIamMember(response: any): void {
const users: User.AsObject[] = response.users;
const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
@ -107,7 +107,7 @@ export class MembershipsComponent implements OnInit {
}
private createOrgMember(response: any): void {
const users: User.AsObject[] = response.users;
const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
@ -122,7 +122,7 @@ export class MembershipsComponent implements OnInit {
}
private createGrantedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {
@ -142,7 +142,7 @@ export class MembershipsComponent implements OnInit {
}
private createOwnedProjectMember(response: any): void {
const users: User.AsObject[] = response.users;
const users: UserView.AsObject[] = response.users;
const roles: string[] = response.roles;
if (users && users.length && roles && roles.length) {

View File

@ -7,7 +7,7 @@ import {
ChangeRequest,
Changes,
CreateUserRequest,
Email,
LoginName,
Gender,
MultiFactors,
NotificationType,
@ -391,11 +391,11 @@ export class MgmtUserService {
);
}
public async GetUserByEmailGlobal(email: string): Promise<User> {
const req = new Email();
req.setEmail(email);
public async GetUserByLoginNameGlobal(loginName: string): Promise<UserView> {
const req = new LoginName();
req.setLoginName(loginName);
return await this.request(
c => c.getUserByEmailGlobal,
c => c.getUserByLoginNameGlobal,
req,
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/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/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
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
}
err = user.AppendEvent(event)
case es_model.DomainClaimed:
case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID)
if err != nil {
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)
}
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email)
func (v *View) GetGlobalUserByLoginName(loginName string) (*model.UserView, error) {
return view.GetGlobalUserByLoginName(v.Db, userTable, loginName)
}
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
}
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) {
email, err := s.repo.ChangeMyEmail(ctx, updateEmailToModel(ctx, request))
if err != nil {

View File

@ -5,8 +5,7 @@ import (
"github.com/golang/protobuf/ptypes/empty"
grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/errors"
"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
}
func (s *Server) GetUserByEmailGlobal(ctx context.Context, email *management.Email) (*management.UserView, error) {
user, err := s.user.GetGlobalUserByEmail(ctx, email.Email)
func (s *Server) GetUserByLoginNameGlobal(ctx context.Context, loginName *management.LoginName) (*management.UserView, error) {
user, err := s.user.GetUserByLoginNameGlobal(ctx, loginName.LoginName)
if err != nil {
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) {
request := userSearchRequestsToModel(in)
orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID)
request.AppendMyOrgQuery(orgID)
request.AppendMyOrgQuery(authz.GetCtxData(ctx).OrgID)
response, err := s.user.SearchUsers(ctx, request)
if err != nil {
return nil, err
@ -106,6 +104,10 @@ func (s *Server) GetUserProfile(ctx context.Context, in *management.UserID) (*ma
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) {
profile, err := s.user.ChangeProfile(ctx, updateProfileToModel(request))
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))
}
}
config.OPConfig.CodeMethodS256 = true
provider, err := op.NewDefaultOP(
ctx,
config.OPConfig,

View File

@ -239,8 +239,11 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
if !user.IsEmailVerified {
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
}

View File

@ -220,6 +220,14 @@ func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error {
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 {
_, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID)
return err
@ -299,6 +307,15 @@ func (repo *UserRepo) MyUserChanges(ctx context.Context, lastSequence uint64, li
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 {
if obj.AggregateID != authz.GetCtxData(ctx).UserID {
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
}
err = user.AppendEvent(event)
case es_model.DomainClaimed:
case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID)
if err != nil {
return err

View File

@ -65,7 +65,9 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.MfaOtpRemoved,
es_model.UserProfileChanged,
es_model.UserLocked,
es_model.UserDeactivated:
es_model.UserDeactivated,
es_model.DomainClaimed,
es_model.UserUserNameChanged:
sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
if err != nil {
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)
}
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email)
func (v *View) GetGlobalUserByLoginName(email string) (*model.UserView, error) {
return view.GetGlobalUserByLoginName(v.Db, userTable, email)
}
func (v *View) IsUserUnique(userName, email string) (bool, error) {

View File

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

View File

@ -21,9 +21,14 @@ type UserRepository interface {
VerifyEmail(ctx context.Context, userID, code 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)
VerifyMfaOTPSetup(ctx context.Context, userID, code string) error
ChangeUsername(ctx context.Context, userID, username string) error
SignOut(ctx context.Context, agentID string) error
UserByID(ctx context.Context, userID string) (*model.UserView, error)
@ -56,5 +61,7 @@ type myUserRepo interface {
VerifyMyMfaOTPSetup(ctx context.Context, code string) 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)
}

View File

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

View File

@ -81,6 +81,7 @@ type Endpoints struct {
InitCode string
PasswordReset string
VerifyEmail string
DomainClaimed string
}
type Providers struct {
@ -94,4 +95,5 @@ type TemplateData struct {
PasswordReset templates.TemplateData
VerifyEmail 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
}
func (repo *UserRepo) GetGlobalUserByEmail(ctx context.Context, email string) (*usr_model.UserView, error) {
user, err := repo.View.GetGlobalUserByEmail(email)
func (repo *UserRepo) GetUserByLoginNameGlobal(ctx context.Context, loginName string) (*usr_model.UserView, error) {
user, err := repo.View.GetGlobalUserByLoginName(loginName)
if err != nil {
return nil, err
}
@ -179,6 +179,14 @@ func (repo *UserRepo) ChangeProfile(ctx context.Context, profile *usr_model.Prof
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) {
user, err := repo.UserByID(ctx, userID)
if err != nil {

View File

@ -80,7 +80,8 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
return err
}
err = user.AppendEvent(event)
case es_model.DomainClaimed:
case es_model.DomainClaimed,
es_model.UserUserNameChanged:
user, err = u.view.UserByID(event.AggregateID)
if err != nil {
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)
}
func (v *View) GetGlobalUserByEmail(email string) (*model.UserView, error) {
return view.GetGlobalUserByEmail(v.Db, userTable, email)
func (v *View) GetGlobalUserByLoginName(loginName string) (*model.UserView, error) {
return view.GetGlobalUserByLoginName(v.Db, userTable, loginName)
}
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)
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)
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)
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)
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)
ChangeEmail(ctx context.Context, email *model.Email) (*model.Email, error)
CreateEmailVerificationCode(ctx context.Context, userID string) error

View File

@ -2,6 +2,7 @@ package handler
import (
"context"
"encoding/json"
"net/http"
"github.com/caos/logging"
@ -9,6 +10,7 @@ import (
"github.com/caos/zitadel/internal/api/authz"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"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/models"
"github.com/caos/zitadel/internal/eventstore/spooler"
@ -56,6 +58,8 @@ func (n *Notification) Reduce(event *models.Event) (err error) {
err = n.handlePhoneVerificationCode(event)
case es_model.UserPasswordCodeAdded:
err = n.handlePasswordCode(event)
case es_model.DomainClaimed:
err = n.handleDomainClaimed(event)
default:
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)
}
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) {
events, err := n.getUserEvents(userID, sequence)
if err != nil {

View File

@ -69,6 +69,17 @@ func (u *NotifyUser) ProcessUser(event *models.Event) (err error) {
return err
}
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:
err = u.view.DeleteNotifyUser(event.AggregateID, event.Sequence)
default:

View File

@ -26,4 +26,10 @@ VerifyPhone:
Greeting: Hallo {{.FirstName}} {{.LastName}},
Text: Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst {{.Code}}
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}},
Text: A new phonenumber has been added. Please use the following code to verify it {{.Code}}
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
EmailAsUsernameNotAllowed: Email is not allowed as username
Invalid: Userdata is invalid
DomainNotAllowedAsUsername: Domain is already reserved
DomainNotAllowedAsUsername: Domain is already reserved and cannot be used
AlreadyInactive: User already inactive
NotInactive: User is not inactive
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/http/middleware"
auth_repository "github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/form"
@ -23,7 +24,7 @@ type Login struct {
router http.Handler
renderer *Renderer
parser *form.Parser
authRepo *eventsourcing.EsRepository
authRepo auth_repository.Repository
zitadelURL string
oidcAuthCallbackURL string
}

View File

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

View File

@ -13,6 +13,7 @@ const (
EndpointLogin = "/login"
EndpointLoginName = "/loginname"
EndpointUserSelection = "/userselection"
EndpointChangeUsername = "/username/change"
EndpointPassword = "/password"
EndpointInitPassword = "/password/init"
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.handleLoginNameCheck).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(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet)
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
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:
Title: Multifaktor verifizieren
Description: Verifiziere deinen Multifaktor
@ -153,6 +162,7 @@ Errors:
NotMatchingUserID: User stimm nicht mit User in Auth Request überein
UserIDMissing: UserID ist leer
Invalid: Userdaten sind ungültig
DomainNotAllowedAsUsername: Domäne ist bereits reserviert und kann nicht verwendet werden
Password:
ConfirmationWrong: Passwort Bestätigung stimmt nicht überein
Empty: Passwort ist leer

View File

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

View File

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

View File

@ -41,7 +41,7 @@
{{ template "error-message" .}}
<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 }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
</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"
name="resend"
value="false"
class="primary right"
{{ if not .PasswordSet }} disabled {{ end }}>{{t "Actions.Next"}}</button>
class="primary right">{{t "Actions.Next"}}</button>
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend" }}</button>
<a href="{{ loginUrl }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>

View File

@ -20,7 +20,7 @@
{{template "error-message" .}}
<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>
</div>
</form>

View File

@ -21,7 +21,7 @@
{{ template "error-message" .}}
<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 }}
<button type="submit" name="resend" value="true" class="secondary right" formnovalidate>{{t "Actions.Resend"}}</button>
{{ end }}

View File

@ -34,7 +34,7 @@
{{end}}
<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 }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a>

View File

@ -21,7 +21,7 @@
{{ template "error-message" .}}
<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 }}">
<button class="secondary" type="button">{{t "Actions.Cancel"}}</button>
</a>

View File

@ -21,7 +21,7 @@
{{template "error-message" .}}
<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 }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a>

View File

@ -61,7 +61,7 @@
{{template "error-message" .}}
<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 }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a>

View File

@ -59,7 +59,7 @@
{{template "error-message" .}}
<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>
</form>

View File

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

View File

@ -670,11 +670,11 @@ func (es *UserEventstore) ChangeEmail(ctx context.Context, email *usr_model.Emai
repoNew := model.EmailFromModel(email)
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 {
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 {
return nil, err
}
@ -1112,6 +1112,48 @@ func (es *UserEventstore) PrepareDomainClaimed(ctx context.Context, userIDs []st
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) {
id, err := es.idGenerator.Next()
if err != nil {

View File

@ -5,7 +5,6 @@ import "github.com/caos/zitadel/internal/eventstore/models"
const (
UserAggregate models.AggregateType = "user"
UserUserNameAggregate models.AggregateType = "user.username"
UserEmailAggregate models.AggregateType = "user.email"
UserAdded models.EventType = "user.added"
UserRegistered models.EventType = "user.selfregistered"
@ -16,8 +15,6 @@ const (
UserUserNameReserved models.EventType = "user.username.reserved"
UserUserNameReleased models.EventType = "user.username.released"
UserEmailReserved models.EventType = "user.email.reserved"
UserEmailReleased models.EventType = "user.email.released"
UserLocked models.EventType = "user.locked"
UserUnlocked models.EventType = "user.unlocked"
@ -44,8 +41,9 @@ const (
UserPhoneCodeAdded models.EventType = "user.phone.code.added"
UserPhoneCodeSent models.EventType = "user.phone.code.sent"
UserProfileChanged models.EventType = "user.profile.changed"
UserAddressChanged models.EventType = "user.address.changed"
UserProfileChanged models.EventType = "user.profile.changed"
UserAddressChanged models.EventType = "user.address.changed"
UserUserNameChanged models.EventType = "user.username.changed"
MfaOtpAdded models.EventType = "user.mfa.otp.added"
MfaOtpVerified models.EventType = "user.mfa.otp.verified"
@ -56,5 +54,6 @@ const (
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,
UserRegistered,
UserProfileChanged,
DomainClaimed:
DomainClaimed,
UserUserNameChanged:
u.setData(event)
case UserDeactivated:
u.appendDeactivatedEvent()

View File

@ -33,14 +33,6 @@ func UserUserNameUniqueQuery(userName string) *es_models.SearchQuery {
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) {
if user == nil {
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 {
return nil, err
}
return []*es_models.Aggregate{
agg,
uniqueAggregates[0],
uniqueAggregates[1],
}, nil
return append(uniqueAggregates, agg), nil
}
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 {
return nil, err
}
return []*es_models.Aggregate{
agg,
uniqueAggregates[0],
uniqueAggregates[1],
}, nil
return append(uniqueAggregates, agg), nil
}
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
}
emailAggregate, err := reservedUniqueEmailAggregate(ctx, aggCreator, resourceOwner, user.EmailAddress)
if err != nil {
return nil, err
}
return []*es_models.Aggregate{
userNameAggregate,
emailAggregate,
}, nil
}
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
}
func reservedUniqueEmailAggregate(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))
}
func changeUniqueUserNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, oldUsername, username string, userLoginMustBeDomain bool) ([]*es_models.Aggregate, error) {
aggregates := make([]*es_models.Aggregate, 2)
var err error
aggregates[0], err = releasedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, oldUsername)
if err != nil {
return nil, err
}
aggregate, err = aggregate.AppendEvent(model.UserEmailReserved, nil)
aggregates[1], err = reservedUniqueUserNameAggregate(ctx, aggCreator, resourceOwner, username, userLoginMustBeDomain)
if err != nil {
return nil, err
}
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
return aggregates, nil
}
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 {
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 {
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)
if err != nil {
return nil, err
@ -446,7 +396,7 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr
return nil, err
}
}
return append(aggregates, agg), nil
return agg, nil
}
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) {
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)
if err != nil {
return nil, err
@ -682,18 +635,41 @@ func DomainClaimedAggregate(ctx context.Context, aggCreator *es_models.Aggregate
if err != nil {
return nil, err
}
aggregates[0] = userAggregate
releasedUniqueAggregate, err := releasedUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, existingUser.UserName)
return append(aggregates, userAggregate), nil
}
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 {
return nil, err
}
aggregates[1] = releasedUniqueAggregate
reservedUniqueAggregate, err := reservedUniqueUserNameAggregate(ctx, aggCreator, existingUser.ResourceOwner, tempName, false)
userAggregate, err := UserAggregate(ctx, aggCreator, user)
if err != nil {
return nil, err
}
aggregates[2] = reservedUniqueAggregate
return aggregates, nil
userAggregate, err = userAggregate.AppendEvent(model.UserUserNameChanged, map[string]interface{}{"userName": user.UserName})
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 {

View File

@ -136,7 +136,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 1,
eventTypes: []models.EventType{model.UserAdded},
checkData: []bool{true},
aggregatesLen: 3,
aggregatesLen: 2,
},
},
{
@ -166,7 +166,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.InitializedUserCodeAdded},
checkData: []bool{true, true},
aggregatesLen: 3,
aggregatesLen: 2,
},
},
{
@ -184,7 +184,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserPhoneCodeAdded},
checkData: []bool{true, true},
aggregatesLen: 3,
aggregatesLen: 2,
},
},
{
@ -201,7 +201,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserEmailVerified},
checkData: []bool{true, false},
aggregatesLen: 3,
aggregatesLen: 2,
},
},
{
@ -219,7 +219,7 @@ func TestUserCreateAggregate(t *testing.T) {
eventLen: 2,
eventTypes: []models.EventType{model.UserAdded, model.UserPhoneVerified},
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))
}
if !tt.res.wantErr && len(aggregates[0].Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events))
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[1].Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if !tt.res.wantErr && aggregates[0].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())
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[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")
}
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")
}
}
@ -352,14 +352,14 @@ func TestUserRegisterAggregate(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)
if tt.res.errFunc == nil && len(aggregates[0].Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events))
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[1].Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if tt.res.errFunc == nil && aggregates[0].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())
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[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")
}
}
@ -1226,16 +1226,16 @@ func TestChangeEmailAggregate(t *testing.T) {
}
for _, tt := range tests {
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 {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events))
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(aggregate.Events))
}
for i := 0; i < tt.res.eventLen; i++ {
if tt.res.errFunc == nil && aggregates[2].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())
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], 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")
}
}

View File

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

View File

@ -94,9 +94,9 @@ func SearchUsers(db *gorm.DB, table string, req *usr_model.UserSearchRequest) ([
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)
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)
if caos_errs.IsNotFound(err) {
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: "",
},
"/caos.zitadel.auth.api.v1.AuthService/ChangeMyUserName": authz.Option{
Permission: "authenticated",
CheckParam: "",
},
"/caos.zitadel.auth.api.v1.AuthService/GetMyUserEmail": authz.Option{
Permission: "authenticated",
CheckParam: "",

View File

@ -1006,6 +1006,45 @@ func (m *UpdateUserProfileRequest) GetGender() Gender {
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 {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,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 (*UserEmail) ProtoMessage() {}
func (*UserEmail) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{6}
return fileDescriptor_8bbd6f3875b0e874, []int{7}
}
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 (*UserEmailView) ProtoMessage() {}
func (*UserEmailView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{7}
return fileDescriptor_8bbd6f3875b0e874, []int{8}
}
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 (*VerifyMyUserEmailRequest) ProtoMessage() {}
func (*VerifyMyUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{8}
return fileDescriptor_8bbd6f3875b0e874, []int{9}
}
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 (*VerifyUserEmailRequest) ProtoMessage() {}
func (*VerifyUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{9}
return fileDescriptor_8bbd6f3875b0e874, []int{10}
}
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 (*UpdateUserEmailRequest) ProtoMessage() {}
func (*UpdateUserEmailRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{10}
return fileDescriptor_8bbd6f3875b0e874, []int{11}
}
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 (*UserPhone) ProtoMessage() {}
func (*UserPhone) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{11}
return fileDescriptor_8bbd6f3875b0e874, []int{12}
}
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 (*UserPhoneView) ProtoMessage() {}
func (*UserPhoneView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{12}
return fileDescriptor_8bbd6f3875b0e874, []int{13}
}
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 (*UpdateUserPhoneRequest) ProtoMessage() {}
func (*UpdateUserPhoneRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{13}
return fileDescriptor_8bbd6f3875b0e874, []int{14}
}
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 (*VerifyUserPhoneRequest) ProtoMessage() {}
func (*VerifyUserPhoneRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{14}
return fileDescriptor_8bbd6f3875b0e874, []int{15}
}
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 (*UserAddress) ProtoMessage() {}
func (*UserAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{15}
return fileDescriptor_8bbd6f3875b0e874, []int{16}
}
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 (*UserAddressView) ProtoMessage() {}
func (*UserAddressView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{16}
return fileDescriptor_8bbd6f3875b0e874, []int{17}
}
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 (*UpdateUserAddressRequest) ProtoMessage() {}
func (*UpdateUserAddressRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{17}
return fileDescriptor_8bbd6f3875b0e874, []int{18}
}
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 (*PasswordID) ProtoMessage() {}
func (*PasswordID) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{18}
return fileDescriptor_8bbd6f3875b0e874, []int{19}
}
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 (*PasswordRequest) ProtoMessage() {}
func (*PasswordRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{19}
return fileDescriptor_8bbd6f3875b0e874, []int{20}
}
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 (*PasswordChange) ProtoMessage() {}
func (*PasswordChange) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{20}
return fileDescriptor_8bbd6f3875b0e874, []int{21}
}
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 (*VerifyMfaOtp) ProtoMessage() {}
func (*VerifyMfaOtp) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{21}
return fileDescriptor_8bbd6f3875b0e874, []int{22}
}
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 (*MultiFactors) ProtoMessage() {}
func (*MultiFactors) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{22}
return fileDescriptor_8bbd6f3875b0e874, []int{23}
}
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 (*MultiFactor) ProtoMessage() {}
func (*MultiFactor) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{23}
return fileDescriptor_8bbd6f3875b0e874, []int{24}
}
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 (*MfaOtpResponse) ProtoMessage() {}
func (*MfaOtpResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{24}
return fileDescriptor_8bbd6f3875b0e874, []int{25}
}
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 (*OIDCClientAuth) ProtoMessage() {}
func (*OIDCClientAuth) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{25}
return fileDescriptor_8bbd6f3875b0e874, []int{26}
}
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 (*UserGrantSearchRequest) ProtoMessage() {}
func (*UserGrantSearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{26}
return fileDescriptor_8bbd6f3875b0e874, []int{27}
}
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 (*UserGrantSearchQuery) ProtoMessage() {}
func (*UserGrantSearchQuery) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{27}
return fileDescriptor_8bbd6f3875b0e874, []int{28}
}
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 (*UserGrantSearchResponse) ProtoMessage() {}
func (*UserGrantSearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{28}
return fileDescriptor_8bbd6f3875b0e874, []int{29}
}
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 (*UserGrantView) ProtoMessage() {}
func (*UserGrantView) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{29}
return fileDescriptor_8bbd6f3875b0e874, []int{30}
}
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 (*MyProjectOrgSearchRequest) ProtoMessage() {}
func (*MyProjectOrgSearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{30}
return fileDescriptor_8bbd6f3875b0e874, []int{31}
}
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 (*MyProjectOrgSearchQuery) ProtoMessage() {}
func (*MyProjectOrgSearchQuery) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{31}
return fileDescriptor_8bbd6f3875b0e874, []int{32}
}
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 (*MyProjectOrgSearchResponse) ProtoMessage() {}
func (*MyProjectOrgSearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{32}
return fileDescriptor_8bbd6f3875b0e874, []int{33}
}
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 (*Org) ProtoMessage() {}
func (*Org) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{33}
return fileDescriptor_8bbd6f3875b0e874, []int{34}
}
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 (*MyPermissions) ProtoMessage() {}
func (*MyPermissions) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{34}
return fileDescriptor_8bbd6f3875b0e874, []int{35}
}
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 (*ChangesRequest) ProtoMessage() {}
func (*ChangesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{35}
return fileDescriptor_8bbd6f3875b0e874, []int{36}
}
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 (*Changes) ProtoMessage() {}
func (*Changes) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{36}
return fileDescriptor_8bbd6f3875b0e874, []int{37}
}
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 (*Change) ProtoMessage() {}
func (*Change) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{37}
return fileDescriptor_8bbd6f3875b0e874, []int{38}
}
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 (*PasswordComplexityPolicy) ProtoMessage() {}
func (*PasswordComplexityPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_8bbd6f3875b0e874, []int{38}
return fileDescriptor_8bbd6f3875b0e874, []int{39}
}
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((*UserProfileView)(nil), "caos.zitadel.auth.api.v1.UserProfileView")
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((*UserEmailView)(nil), "caos.zitadel.auth.api.v1.UserEmailView")
proto.RegisterType((*VerifyMyUserEmailRequest)(nil), "caos.zitadel.auth.api.v1.VerifyMyUserEmailRequest")
@ -3075,239 +3115,242 @@ func init() {
func init() { proto.RegisterFile("auth.proto", fileDescriptor_8bbd6f3875b0e874) }
var fileDescriptor_8bbd6f3875b0e874 = []byte{
// 3566 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x5f, 0x6f, 0x1b, 0xd7,
0x95, 0xf7, 0x90, 0x94, 0x44, 0x1e, 0x4a, 0x14, 0x75, 0x2d, 0x4b, 0x14, 0x65, 0xd9, 0xf2, 0x38,
0x8e, 0x65, 0xc6, 0x16, 0x63, 0x25, 0xc1, 0xda, 0x0e, 0xb0, 0x01, 0x2d, 0xd2, 0x12, 0xd7, 0xe2,
0x9f, 0x0c, 0x29, 0x67, 0x1d, 0x60, 0x41, 0x8c, 0x38, 0x57, 0xd4, 0x24, 0x43, 0x0e, 0x33, 0x33,
0x94, 0x96, 0x01, 0x36, 0xc0, 0x7a, 0x17, 0x9b, 0x5d, 0x60, 0xb3, 0xbb, 0xc8, 0x2e, 0x16, 0x28,
0x8a, 0x3e, 0x14, 0x68, 0x8b, 0x3e, 0x14, 0xed, 0x43, 0xd1, 0x02, 0x45, 0xfb, 0x01, 0xfa, 0xd2,
0x87, 0xa2, 0x40, 0x3f, 0x40, 0xd1, 0xaf, 0x50, 0x14, 0x4d, 0x5f, 0x8a, 0xfb, 0x67, 0x86, 0xc3,
0x19, 0x0e, 0x49, 0xd9, 0x4d, 0x1b, 0x04, 0x79, 0x12, 0xef, 0xf9, 0x77, 0xcf, 0x3d, 0xe7, 0x77,
0xef, 0x3d, 0x73, 0x8f, 0x00, 0xe4, 0x9e, 0x75, 0xb2, 0xdd, 0x35, 0x74, 0x4b, 0x47, 0xa9, 0xa6,
0xac, 0x9b, 0xdb, 0x1f, 0xaa, 0x96, 0xac, 0x60, 0x6d, 0x9b, 0x32, 0xe4, 0xae, 0xba, 0x7d, 0x7a,
0x37, 0x7d, 0xb9, 0xa5, 0xeb, 0x2d, 0x0d, 0x67, 0xe5, 0xae, 0x9a, 0x95, 0x3b, 0x1d, 0xdd, 0x92,
0x2d, 0x55, 0xef, 0x98, 0x4c, 0x2f, 0xbd, 0xce, 0xb9, 0x74, 0x74, 0xd4, 0x3b, 0xce, 0xe2, 0x76,
0xd7, 0xea, 0x73, 0xe6, 0x65, 0x2f, 0xd3, 0xb4, 0x8c, 0x5e, 0xd3, 0xe2, 0xdc, 0xab, 0x5e, 0xae,
0xa5, 0xb6, 0xb1, 0x69, 0xc9, 0xed, 0x2e, 0x17, 0x58, 0x3d, 0x95, 0x35, 0x55, 0x91, 0x2d, 0x9c,
0xb5, 0x7f, 0x70, 0xc6, 0x6d, 0xfa, 0xa7, 0x79, 0xa7, 0x85, 0x3b, 0x77, 0xcc, 0x33, 0xb9, 0xd5,
0xc2, 0x46, 0x56, 0xef, 0x52, 0xb7, 0x46, 0xb8, 0x98, 0x22, 0xab, 0x61, 0x6c, 0x5b, 0x8a, 0x73,
0x2e, 0xd2, 0x3f, 0xd9, 0x36, 0x36, 0x4d, 0xb9, 0xc5, 0x8d, 0x8b, 0x47, 0x90, 0x3c, 0x34, 0xb1,
0x51, 0xc3, 0xa6, 0xa9, 0xea, 0x9d, 0x27, 0x2a, 0x3e, 0x33, 0x51, 0x19, 0x16, 0x7a, 0x26, 0x36,
0x1a, 0x26, 0x23, 0x9a, 0x29, 0x61, 0x33, 0xbc, 0x15, 0xdf, 0xb9, 0xb5, 0x1d, 0x14, 0xb5, 0x6d,
0x8f, 0x09, 0x69, 0xbe, 0x37, 0x20, 0x98, 0xe2, 0xd7, 0x43, 0xb0, 0xe8, 0x91, 0x40, 0x09, 0x08,
0xa9, 0x4a, 0x4a, 0xd8, 0x14, 0xb6, 0x62, 0x52, 0x48, 0x55, 0xd0, 0x1a, 0x44, 0xe5, 0x16, 0xee,
0x58, 0x0d, 0x55, 0x49, 0x85, 0x28, 0x75, 0x8e, 0x8e, 0x8b, 0x0a, 0x2a, 0xb2, 0xd4, 0x35, 0x4c,
0x4b, 0xb6, 0x70, 0x2a, 0xbc, 0x29, 0x6c, 0x25, 0x76, 0x32, 0x53, 0xf9, 0x52, 0x23, 0x1a, 0x52,
0x8c, 0x70, 0xe9, 0x4f, 0xb4, 0x0a, 0x73, 0x74, 0x65, 0xaa, 0x92, 0x8a, 0xd0, 0x49, 0x66, 0xc9,
0xb0, 0xa8, 0xa0, 0x75, 0x88, 0x51, 0x46, 0x47, 0x6e, 0xe3, 0xd4, 0x0c, 0x65, 0x45, 0x09, 0xa1,
0x2c, 0xb7, 0x31, 0x4a, 0x43, 0xd4, 0xc4, 0x1f, 0xf4, 0x70, 0xa7, 0x89, 0x53, 0xb3, 0x9b, 0xc2,
0x56, 0x44, 0x72, 0xc6, 0x68, 0x03, 0x40, 0xd3, 0x5b, 0x6a, 0x87, 0x69, 0xce, 0x51, 0xcd, 0x18,
0xa5, 0x50, 0xd5, 0x6b, 0x30, 0xaf, 0xa8, 0x66, 0x57, 0x93, 0xfb, 0x4c, 0x20, 0x4a, 0x05, 0xe2,
0x9c, 0x46, 0x44, 0xc4, 0x8f, 0xa3, 0x10, 0x25, 0x3e, 0x8f, 0x0c, 0xcb, 0x7d, 0x98, 0x61, 0xcb,
0x0e, 0xd1, 0x65, 0x5f, 0x9f, 0xb0, 0x6c, 0xba, 0x5e, 0xa6, 0x81, 0xde, 0x82, 0x85, 0xa6, 0x81,
0x29, 0x36, 0x1a, 0x8a, 0x1d, 0xb9, 0xf8, 0x4e, 0x7a, 0x9b, 0x01, 0x71, 0xdb, 0x06, 0xe2, 0x76,
0xdd, 0x06, 0xa2, 0x34, 0x6f, 0x2b, 0xe4, 0x89, 0x81, 0x37, 0x21, 0xde, 0x3c, 0x91, 0x3b, 0x2d,
0xcc, 0xd4, 0x23, 0x13, 0xd5, 0x81, 0x89, 0x53, 0xe5, 0xfb, 0x00, 0x9a, 0x6c, 0x5a, 0x0d, 0x1a,
0x0a, 0x1a, 0xd1, 0xf1, 0xba, 0x31, 0x22, 0x7d, 0x40, 0x84, 0x51, 0x01, 0x92, 0x5d, 0xd9, 0x34,
0xcf, 0x74, 0x43, 0x69, 0x30, 0x8b, 0x0a, 0x0d, 0xfb, 0x78, 0x03, 0x8b, 0xb6, 0xce, 0x2e, 0x53,
0x19, 0x4e, 0xe9, 0x9c, 0x27, 0xa5, 0x1b, 0x00, 0xc7, 0xaa, 0x61, 0x5a, 0xee, 0xac, 0xc4, 0x28,
0x85, 0xb2, 0xd7, 0x81, 0xfa, 0xc3, 0xb8, 0x31, 0xa6, 0x4b, 0x08, 0x23, 0x73, 0x0a, 0xbe, 0x9c,
0x12, 0xfd, 0x8e, 0xda, 0x7c, 0x9f, 0xf1, 0xe3, 0x4c, 0x9f, 0x10, 0x28, 0xf3, 0x0e, 0xa0, 0xae,
0x81, 0x8f, 0xb1, 0x61, 0x60, 0xa5, 0xa1, 0xc9, 0x9d, 0x56, 0x4f, 0x6e, 0xe1, 0xd4, 0x3c, 0x95,
0x5a, 0x72, 0x38, 0x07, 0x9c, 0x81, 0xee, 0xc1, 0x6c, 0x0b, 0x77, 0x14, 0x6c, 0xa4, 0x16, 0x28,
0x06, 0x36, 0x83, 0x31, 0xb0, 0x47, 0xe5, 0x24, 0x2e, 0x8f, 0x96, 0x61, 0x06, 0xb7, 0x65, 0x55,
0x4b, 0x25, 0xa8, 0x6d, 0x36, 0x40, 0x19, 0x58, 0x52, 0xcd, 0x06, 0xfd, 0xdd, 0x38, 0xc5, 0x86,
0x7a, 0xac, 0x62, 0x25, 0xb5, 0xb8, 0x29, 0x6c, 0x45, 0xa5, 0x45, 0xd5, 0x2c, 0x10, 0xfa, 0x13,
0x4e, 0x26, 0x16, 0xba, 0x27, 0x7a, 0x07, 0xa7, 0x92, 0xcc, 0x02, 0x1d, 0x70, 0x0b, 0xf4, 0xf7,
0xc0, 0xc2, 0x92, 0x6d, 0xa1, 0x4a, 0xe8, 0x8e, 0x85, 0x14, 0xcc, 0x35, 0xf5, 0x5e, 0xc7, 0x32,
0xfa, 0x29, 0xc4, 0xb6, 0x35, 0x1f, 0x92, 0x5d, 0xa5, 0xe9, 0x4d, 0x59, 0x53, 0xad, 0x7e, 0xea,
0x22, 0x0f, 0x31, 0x1f, 0xa3, 0xab, 0x10, 0xef, 0xea, 0xa6, 0x25, 0x6b, 0x8d, 0xa6, 0xae, 0xe0,
0xd4, 0x32, 0x65, 0x03, 0x23, 0xed, 0xea, 0x0a, 0x46, 0x2b, 0x30, 0x6b, 0xe0, 0x96, 0xaa, 0x77,
0x52, 0x97, 0xd8, 0x3e, 0x66, 0x23, 0x74, 0x03, 0x12, 0xa6, 0x65, 0x60, 0x6c, 0x35, 0x64, 0x45,
0x31, 0xb0, 0x69, 0xa6, 0x56, 0x28, 0x7f, 0x81, 0x51, 0x73, 0x8c, 0x38, 0xb4, 0xa3, 0x57, 0x3d,
0x3b, 0xfa, 0x06, 0x24, 0x0c, 0x6c, 0xea, 0x3d, 0xa3, 0x89, 0x1b, 0xfa, 0x59, 0x07, 0x1b, 0xa9,
0x14, 0x33, 0x61, 0x53, 0x2b, 0x84, 0x48, 0x5c, 0x1c, 0x6c, 0x7c, 0x33, 0xb5, 0xb6, 0x19, 0x26,
0x2e, 0x3a, 0x3b, 0xdf, 0x44, 0xaf, 0xc2, 0xb2, 0x2b, 0xcd, 0x83, 0x33, 0x22, 0x4d, 0xad, 0x0d,
0x20, 0x70, 0x60, 0xab, 0x88, 0x3f, 0x09, 0x43, 0x9c, 0x6c, 0xe3, 0xaa, 0xa1, 0x1f, 0xab, 0x1a,
0xf6, 0x1d, 0x06, 0x43, 0x88, 0x0e, 0x8d, 0x45, 0x74, 0x78, 0x2c, 0xa2, 0x23, 0x1e, 0x44, 0x0f,
0xc1, 0x75, 0xc6, 0x03, 0x57, 0x2f, 0xdc, 0x67, 0xfd, 0x70, 0x1f, 0x8d, 0xe8, 0xb9, 0xc9, 0x88,
0x8e, 0x9e, 0x13, 0xd1, 0xee, 0xbc, 0xc5, 0x3c, 0x79, 0xf3, 0x9d, 0x77, 0xf0, 0x62, 0xe7, 0x5d,
0xfc, 0x3c, 0xe7, 0x9d, 0xf8, 0x3f, 0x11, 0x76, 0xc7, 0xf1, 0xdc, 0x8d, 0x3c, 0xcc, 0xbf, 0xca,
0xdf, 0x17, 0x36, 0x7f, 0xde, 0xed, 0x3c, 0x3f, 0xf5, 0x76, 0x5e, 0x08, 0xdc, 0xce, 0xff, 0x19,
0x82, 0xd4, 0x61, 0x97, 0xf8, 0xe2, 0x02, 0x86, 0x44, 0x96, 0x6b, 0x5a, 0xe8, 0xd6, 0x50, 0xba,
0x29, 0x46, 0x1e, 0xc2, 0x67, 0x0f, 0xe7, 0x8c, 0x99, 0xa4, 0x90, 0xfa, 0xb9, 0xe0, 0x4e, 0xfd,
0x4d, 0x77, 0xea, 0x43, 0x3e, 0xc9, 0x01, 0x0c, 0x6e, 0xba, 0x61, 0x10, 0xf6, 0x0b, 0x3a, 0x90,
0xb8, 0x3f, 0x32, 0xdf, 0x11, 0x9f, 0xc6, 0xd8, 0xdc, 0xcf, 0x9c, 0x2f, 0xf7, 0xe2, 0xef, 0x04,
0x88, 0x91, 0x40, 0xd0, 0x1b, 0xc6, 0xb7, 0x37, 0x9c, 0xbb, 0x2a, 0xe4, 0xbe, 0xab, 0xb6, 0xc0,
0x7b, 0x25, 0xd1, 0x75, 0x8d, 0xb8, 0xa9, 0xdc, 0xc8, 0x8a, 0x4c, 0x42, 0xd6, 0xcc, 0x8b, 0x21,
0x6b, 0xf6, 0x5c, 0x27, 0xc3, 0x1f, 0x04, 0x58, 0x70, 0xd6, 0x3d, 0xf2, 0x5c, 0xf8, 0xf2, 0xae,
0xfd, 0x01, 0xa4, 0xa8, 0x97, 0xfd, 0x52, 0xdf, 0x09, 0x81, 0xbd, 0x03, 0xae, 0x40, 0x84, 0x5e,
0xee, 0x7e, 0xec, 0x53, 0xba, 0xb8, 0x0f, 0x2b, 0x4c, 0xd7, 0xa7, 0xe9, 0x8d, 0x9f, 0x6d, 0x29,
0x14, 0x60, 0xe9, 0x01, 0xac, 0x0c, 0xf6, 0xe1, 0x90, 0xa5, 0x4d, 0x3b, 0xf2, 0x7e, 0x27, 0x18,
0x43, 0xfc, 0x3d, 0x47, 0x2d, 0xad, 0x6a, 0x46, 0x65, 0x8e, 0xd5, 0x47, 0xa1, 0x89, 0xf5, 0x51,
0x78, 0x74, 0x7d, 0xf4, 0xc5, 0xcd, 0xdd, 0x1f, 0x39, 0x6e, 0x99, 0xbf, 0x01, 0xb8, 0xfd, 0xd2,
0xae, 0xfe, 0xbe, 0x1b, 0x33, 0xd4, 0x69, 0x1b, 0x33, 0x57, 0xed, 0x55, 0x33, 0xcc, 0xc4, 0x3e,
0x7b, 0x38, 0x6b, 0x44, 0x92, 0x42, 0x6a, 0x99, 0x07, 0x40, 0xbc, 0xe7, 0x06, 0xee, 0x90, 0xea,
0x24, 0xc8, 0xff, 0x22, 0xc4, 0x0a, 0x40, 0xbb, 0x4c, 0xf5, 0x06, 0xdc, 0x55, 0x4c, 0x87, 0x82,
0x8b, 0xe9, 0xf0, 0xf8, 0x62, 0x3a, 0x32, 0xa6, 0x98, 0x9e, 0x99, 0x50, 0x4c, 0xcf, 0x4e, 0x2a,
0xa6, 0xe7, 0x26, 0x25, 0x31, 0xfa, 0x62, 0x49, 0x8c, 0x9d, 0x2b, 0x89, 0xbf, 0xe4, 0x0f, 0x0f,
0xdc, 0xd3, 0x91, 0x20, 0xfe, 0x2a, 0xa6, 0xe7, 0x8b, 0xe9, 0x6f, 0x04, 0x77, 0x55, 0xc3, 0xfd,
0xb5, 0x01, 0x2e, 0x0e, 0x82, 0xc9, 0x30, 0x1e, 0xfd, 0xec, 0xe1, 0x8c, 0x11, 0x26, 0x08, 0x77,
0xc2, 0xfa, 0x92, 0x2b, 0xac, 0x21, 0x8f, 0xd0, 0x20, 0xc0, 0xb7, 0x86, 0x03, 0x1c, 0xf6, 0x08,
0xba, 0x43, 0xbd, 0xe9, 0x84, 0x3a, 0xe2, 0x91, 0xb2, 0x83, 0x9e, 0xf5, 0x05, 0x7d, 0xc6, 0x23,
0x39, 0x1c, 0x7e, 0xf1, 0x32, 0x40, 0x95, 0x3f, 0x27, 0x14, 0xf3, 0x5e, 0xc8, 0x88, 0xf7, 0x60,
0xd1, 0xe6, 0xda, 0x0b, 0xbf, 0x01, 0x51, 0xfb, 0xfd, 0xc1, 0x7b, 0x2e, 0xec, 0x4b, 0x0e, 0x4b,
0xd4, 0x20, 0x51, 0x1d, 0x7a, 0xa6, 0x40, 0xb7, 0x61, 0x5e, 0xd7, 0x94, 0x46, 0xb0, 0x72, 0x5c,
0xd7, 0x14, 0x5b, 0x87, 0x48, 0x77, 0xf0, 0xd9, 0x40, 0x3a, 0xe4, 0x93, 0xee, 0xe0, 0x33, 0x5b,
0x5a, 0x14, 0x61, 0x9e, 0xdf, 0xbe, 0xc7, 0x72, 0xc5, 0xea, 0x22, 0xe4, 0x3e, 0x7e, 0xf8, 0x91,
0x53, 0x84, 0xf9, 0x52, 0x4f, 0xb3, 0xd4, 0x47, 0x72, 0xd3, 0xd2, 0x0d, 0x13, 0xdd, 0x87, 0x48,
0xfb, 0x58, 0xb6, 0x9f, 0xfc, 0x6e, 0x04, 0x57, 0x77, 0x2e, 0x2d, 0x89, 0xaa, 0x88, 0x1f, 0x41,
0xdc, 0x45, 0x44, 0x6f, 0x40, 0xc4, 0xea, 0x77, 0xd9, 0x6c, 0x89, 0x9d, 0x6b, 0x63, 0x2c, 0x1d,
0xcb, 0xf5, 0x7e, 0x17, 0x4b, 0x54, 0x1c, 0xdd, 0x1b, 0x7e, 0xf1, 0x12, 0xc7, 0xe8, 0x3d, 0xca,
0xb9, 0x1f, 0xbc, 0xc4, 0x4f, 0x04, 0x48, 0xb0, 0x95, 0x4a, 0xd8, 0xec, 0xea, 0x1d, 0x73, 0xe8,
0xbd, 0x4f, 0x18, 0x7a, 0xef, 0x4b, 0x42, 0xb8, 0x67, 0xd8, 0x05, 0x17, 0xf9, 0x49, 0x36, 0xac,
0x89, 0x9b, 0x06, 0xb6, 0xf8, 0x5e, 0xe7, 0xa3, 0x81, 0x3f, 0x91, 0xf3, 0xfa, 0x23, 0x41, 0xa2,
0x52, 0xcc, 0xef, 0xee, 0x6a, 0x2a, 0xee, 0x58, 0xb9, 0x9e, 0x75, 0x42, 0xbe, 0xd3, 0x9a, 0x74,
0x34, 0x70, 0x28, 0xca, 0x08, 0x45, 0x05, 0x5d, 0x87, 0x05, 0xce, 0xe4, 0x7e, 0x30, 0xe7, 0xe6,
0x19, 0xb1, 0x46, 0x69, 0xe2, 0x3f, 0x87, 0x60, 0x85, 0xec, 0xbb, 0x3d, 0x43, 0x26, 0x34, 0xd9,
0x68, 0x9e, 0xd8, 0x10, 0x5c, 0x81, 0x59, 0xfd, 0xf8, 0xd8, 0xc4, 0x16, 0xb5, 0x1c, 0x91, 0xf8,
0x88, 0xdc, 0xd2, 0x9a, 0xda, 0x56, 0x99, 0xbd, 0x88, 0xc4, 0x06, 0xe8, 0x1f, 0x20, 0x61, 0xea,
0x86, 0xa5, 0x76, 0x5a, 0x8d, 0xa6, 0xae, 0xf5, 0xda, 0x1d, 0xfe, 0xb0, 0x7a, 0x7b, 0xfc, 0x0b,
0xa3, 0x6b, 0xde, 0xc7, 0xb8, 0x4f, 0x37, 0xd0, 0x33, 0x21, 0xb4, 0x79, 0x41, 0x5a, 0xe0, 0xd6,
0x76, 0xa9, 0x31, 0x12, 0x5f, 0xd9, 0x6c, 0xd2, 0x98, 0x45, 0x25, 0xf2, 0x13, 0xed, 0xc3, 0xdc,
0x07, 0x3d, 0x6c, 0xa8, 0x98, 0x6c, 0x3e, 0x82, 0xad, 0xed, 0xa9, 0x67, 0x7a, 0xbb, 0x87, 0x8d,
0xbe, 0x64, 0xab, 0x8b, 0x3f, 0x16, 0x60, 0x79, 0x94, 0x04, 0xda, 0x87, 0xf0, 0xfb, 0xb8, 0xcf,
0x01, 0xf7, 0xbc, 0x0b, 0x21, 0x26, 0xd0, 0xdf, 0xc2, 0x6c, 0x1b, 0x5b, 0x27, 0xba, 0xc2, 0x51,
0xf8, 0x72, 0xb0, 0x31, 0x66, 0xa3, 0x44, 0xa5, 0x25, 0xae, 0x45, 0x62, 0x7e, 0x2a, 0x6b, 0x3d,
0xfb, 0x3b, 0x9e, 0x0d, 0xc4, 0x6f, 0x84, 0x60, 0xd5, 0x97, 0x3c, 0x8e, 0xd4, 0xf3, 0x65, 0xef,
0x1a, 0xcc, 0x5b, 0x3a, 0x39, 0x1c, 0x0d, 0x6c, 0xf6, 0x34, 0x06, 0xd9, 0x88, 0x14, 0xa7, 0x34,
0x89, 0x92, 0xd0, 0x5b, 0xe4, 0x54, 0xa4, 0xcc, 0x08, 0x0d, 0xf7, 0xcd, 0x29, 0xe2, 0x41, 0xdf,
0xee, 0xb9, 0x1a, 0x7b, 0x14, 0xd0, 0x9b, 0xd8, 0x34, 0xb1, 0xd2, 0x70, 0x2e, 0xa3, 0x19, 0x3a,
0xd3, 0x92, 0xc3, 0xa9, 0xd9, 0xb7, 0x52, 0x0e, 0x12, 0xa7, 0x2a, 0x3e, 0x6b, 0x38, 0x6d, 0x8d,
0x29, 0x0a, 0xae, 0x05, 0xa2, 0xe1, 0x0c, 0xc5, 0x6f, 0xf3, 0x8a, 0xd3, 0xf1, 0x85, 0xac, 0xbe,
0x62, 0xb4, 0x8a, 0xf6, 0x66, 0x61, 0x03, 0x74, 0x19, 0x62, 0x55, 0x43, 0x7f, 0x0f, 0x37, 0xad,
0xa2, 0xdd, 0x2c, 0x18, 0x10, 0x48, 0x24, 0x0f, 0xe9, 0x26, 0xb7, 0x37, 0x32, 0x1b, 0x11, 0x5b,
0x92, 0xae, 0x61, 0x93, 0xc6, 0x23, 0x26, 0xb1, 0x01, 0xb9, 0xfe, 0x2b, 0x46, 0xab, 0x3c, 0x78,
0x38, 0xb1, 0x87, 0x84, 0x43, 0x1d, 0x29, 0x2a, 0xfc, 0x8a, 0xb6, 0x87, 0xe2, 0x77, 0x05, 0x58,
0x2b, 0xf5, 0xf9, 0x8c, 0x15, 0xa3, 0xf5, 0x22, 0xfb, 0xd0, 0xbf, 0x51, 0x1e, 0x7b, 0x37, 0xca,
0xdd, 0x31, 0x47, 0x8e, 0xcf, 0x0b, 0xcf, 0x5e, 0xf9, 0x99, 0x00, 0xab, 0x01, 0x42, 0xe8, 0xb1,
0x7b, 0xbb, 0x64, 0xcf, 0x33, 0xc9, 0x5f, 0x6c, 0xc7, 0x7c, 0x4b, 0x80, 0xf4, 0xa8, 0x48, 0x7f,
0x5e, 0x9b, 0xe6, 0x0d, 0xcf, 0xa6, 0xd9, 0x08, 0x5e, 0x45, 0xc5, 0x68, 0xd9, 0x5b, 0x45, 0xbc,
0x05, 0xe1, 0x8a, 0xd1, 0xf2, 0x95, 0x96, 0x08, 0x22, 0xae, 0xa7, 0x3e, 0xfa, 0x5b, 0xbc, 0x0b,
0x0b, 0xa5, 0x7e, 0x15, 0x1b, 0x6d, 0x95, 0x35, 0xc7, 0xd0, 0x26, 0xc4, 0xbb, 0x83, 0x21, 0xbd,
0x77, 0x63, 0x92, 0x9b, 0x24, 0xca, 0x90, 0x60, 0xc5, 0x82, 0x53, 0x66, 0x39, 0xeb, 0x13, 0xdc,
0xeb, 0xbb, 0x09, 0x8b, 0xf6, 0x36, 0x6d, 0xf0, 0xb0, 0xb0, 0xf5, 0x27, 0x6c, 0x72, 0x85, 0x85,
0x87, 0x63, 0x2e, 0xec, 0x60, 0x4e, 0x34, 0x61, 0x8e, 0x4f, 0x81, 0x1e, 0xc0, 0x1c, 0xab, 0xf6,
0xec, 0x1a, 0x60, 0xcc, 0x0b, 0x0f, 0xd3, 0x91, 0x6c, 0x05, 0x57, 0x3e, 0x42, 0xa3, 0xf3, 0x11,
0x76, 0xf9, 0x2b, 0xfe, 0x47, 0x08, 0x66, 0x79, 0x15, 0xe4, 0xa9, 0x48, 0x85, 0x73, 0x3d, 0xdd,
0xe5, 0x01, 0xf0, 0x29, 0xb9, 0x37, 0x69, 0xb9, 0x11, 0xa2, 0xba, 0xde, 0xc2, 0x85, 0xf9, 0x7b,
0x40, 0xab, 0xcb, 0x0f, 0xb1, 0x52, 0x62, 0x3d, 0x50, 0x29, 0x46, 0x15, 0x49, 0xf5, 0x31, 0x54,
0x71, 0x87, 0x3d, 0x15, 0xf7, 0x3a, 0xc4, 0xb0, 0xa2, 0x5a, 0xba, 0xab, 0x71, 0x18, 0x65, 0x04,
0x76, 0xde, 0xb0, 0xdf, 0x76, 0xa5, 0xcf, 0x46, 0xe8, 0x15, 0x88, 0x28, 0xb2, 0x25, 0xf3, 0x63,
0x70, 0xd5, 0xb7, 0x98, 0x1a, 0xed, 0x0e, 0x4b, 0x54, 0x48, 0xfc, 0x5e, 0x18, 0x52, 0x4e, 0x65,
0xa8, 0xb7, 0xbb, 0x1a, 0xfe, 0x47, 0xd5, 0xea, 0x57, 0x75, 0x4d, 0x6d, 0xf6, 0x7d, 0xb8, 0xda,
0x84, 0xb8, 0x82, 0xcd, 0xa6, 0xa1, 0xd2, 0xf6, 0x2e, 0x87, 0x97, 0x9b, 0xf4, 0x57, 0xee, 0xfd,
0x6d, 0x00, 0xb4, 0xd5, 0x4e, 0x43, 0xc3, 0x9d, 0x96, 0x75, 0xc2, 0x6f, 0x8c, 0x58, 0x5b, 0xed,
0x1c, 0x50, 0x02, 0x29, 0x74, 0x4e, 0x64, 0xb3, 0xa1, 0xe9, 0x67, 0xd8, 0x68, 0xca, 0x26, 0xfb,
0x32, 0x8f, 0x4a, 0xf3, 0x27, 0xb2, 0x79, 0x60, 0xd3, 0x6c, 0xa1, 0x5e, 0xb7, 0xcb, 0x85, 0xe6,
0x1c, 0xa1, 0x43, 0x9b, 0x46, 0x26, 0x22, 0x42, 0x9d, 0x5e, 0xfb, 0x88, 0x3f, 0x46, 0x47, 0xa5,
0xd8, 0x89, 0x6c, 0x96, 0x29, 0xc1, 0x66, 0x9b, 0xfd, 0xf6, 0x91, 0xae, 0xd1, 0xcf, 0x1c, 0xc6,
0xae, 0x51, 0xc2, 0x50, 0xc6, 0xc1, 0xdf, 0xd6, 0x55, 0xcd, 0x86, 0x82, 0x8f, 0x65, 0x72, 0x18,
0xc4, 0x99, 0xaa, 0x6a, 0xe6, 0x19, 0x21, 0x63, 0x0c, 0x75, 0xcd, 0x59, 0x6f, 0x79, 0x13, 0x2e,
0x1f, 0xd6, 0x0a, 0x52, 0xad, 0x50, 0xab, 0x15, 0x2b, 0xe5, 0x5a, 0x3d, 0x57, 0x2f, 0x34, 0x0e,
0xcb, 0xb5, 0x6a, 0x61, 0xb7, 0xf8, 0xa8, 0x58, 0xc8, 0x27, 0x2f, 0xa0, 0x75, 0x58, 0xf5, 0x49,
0xe4, 0x76, 0xeb, 0xc5, 0x27, 0x85, 0xa4, 0x80, 0xae, 0xc2, 0xba, 0x8f, 0x59, 0x2f, 0x48, 0xa5,
0x62, 0x39, 0x57, 0x2f, 0xe4, 0x93, 0xa1, 0xcc, 0x07, 0x90, 0x24, 0xe5, 0xa4, 0x7d, 0xf8, 0x51,
0xd0, 0xae, 0xc1, 0x25, 0x4a, 0x2b, 0xd4, 0xaa, 0x95, 0x72, 0xad, 0x50, 0x7f, 0x5a, 0x2d, 0x34,
0x76, 0x2b, 0xf9, 0x42, 0xf2, 0x02, 0xda, 0x80, 0x35, 0x1f, 0xab, 0x98, 0x6f, 0xd4, 0x2b, 0x8f,
0x0b, 0xe5, 0xa4, 0x80, 0xae, 0xc3, 0xd5, 0x40, 0x36, 0x17, 0x0a, 0x65, 0x7e, 0xc0, 0x1f, 0xbf,
0xd8, 0x02, 0xd7, 0xe0, 0x12, 0xf5, 0x70, 0xc4, 0xca, 0x96, 0x21, 0x39, 0x60, 0x39, 0x4b, 0x5a,
0x01, 0x34, 0xa0, 0x16, 0xcb, 0x9c, 0x1e, 0x42, 0x97, 0x60, 0x69, 0x40, 0xcf, 0x17, 0x0e, 0x0a,
0x64, 0x81, 0xe1, 0x61, 0x23, 0x07, 0x95, 0xdd, 0xc7, 0x85, 0x7c, 0x32, 0x32, 0x2c, 0x5c, 0x3b,
0xac, 0x55, 0x0b, 0xe5, 0x7c, 0x72, 0x66, 0x98, 0x5c, 0x2c, 0x17, 0xeb, 0xc5, 0xdc, 0x41, 0x72,
0x36, 0xf3, 0xf7, 0x30, 0xcb, 0x9e, 0x9d, 0xc9, 0xe4, 0x7b, 0x85, 0x72, 0xbe, 0x20, 0x79, 0x5c,
0x5d, 0x82, 0x05, 0x4e, 0x7f, 0x54, 0x28, 0xe5, 0x0e, 0x88, 0x9f, 0x8b, 0x10, 0xe7, 0x24, 0x4a,
0x08, 0x21, 0x04, 0x09, 0x4e, 0xc8, 0x17, 0x9f, 0x90, 0x9c, 0x24, 0xc3, 0x99, 0x3c, 0xcc, 0xf1,
0x0f, 0x15, 0xb4, 0x0a, 0x17, 0x4b, 0x8f, 0x72, 0x34, 0x64, 0xc3, 0xb6, 0x17, 0x21, 0x6e, 0x33,
0x6a, 0xa5, 0x1a, 0xb3, 0x6c, 0x13, 0x2a, 0xf5, 0x6a, 0x32, 0x94, 0x39, 0x86, 0xa8, 0xfd, 0x99,
0x80, 0x52, 0xb0, 0x4c, 0x7e, 0x8f, 0x08, 0xe7, 0x0a, 0x20, 0x87, 0x53, 0xae, 0xd4, 0x1b, 0x52,
0x21, 0x97, 0x7f, 0x9a, 0x14, 0x88, 0x5f, 0x0e, 0x9d, 0xd1, 0x42, 0x24, 0x6a, 0x2e, 0x5a, 0xa9,
0xf2, 0x84, 0xc4, 0x32, 0x73, 0x0a, 0xc8, 0x5f, 0xe5, 0xa2, 0x2b, 0x90, 0xf6, 0x53, 0x1b, 0x87,
0xe5, 0xc7, 0xe5, 0xca, 0x3b, 0x65, 0x86, 0x99, 0x11, 0xfc, 0x8a, 0xb4, 0xd7, 0x28, 0xe6, 0x93,
0x02, 0xba, 0x06, 0x1b, 0x23, 0xd8, 0x55, 0xa9, 0xf2, 0x77, 0x85, 0xdd, 0x3a, 0x11, 0x09, 0x65,
0x8e, 0xe0, 0xd2, 0xc8, 0x72, 0x01, 0xdd, 0x80, 0x6b, 0xa5, 0xa7, 0x5c, 0xb4, 0x22, 0xed, 0xd5,
0x0a, 0x39, 0x69, 0x77, 0xff, 0x71, 0xe1, 0xa9, 0x67, 0xe5, 0x22, 0x5c, 0x19, 0x2d, 0x46, 0x9c,
0x28, 0xe7, 0x4a, 0x85, 0xa4, 0x90, 0xf9, 0xb5, 0x00, 0xf3, 0xee, 0x1a, 0x82, 0xe4, 0x83, 0x09,
0x96, 0x0a, 0xf5, 0xfd, 0x4a, 0xbe, 0x51, 0x78, 0xfb, 0x30, 0x77, 0x50, 0x4b, 0x5e, 0x40, 0x97,
0x21, 0x35, 0xc4, 0xa8, 0xd5, 0x73, 0x52, 0xbd, 0xd6, 0x78, 0xa7, 0x58, 0xdf, 0x4f, 0x0a, 0x04,
0xcf, 0x43, 0xdc, 0xdd, 0x4a, 0xb9, 0x9e, 0x2b, 0x96, 0x6b, 0xc9, 0x10, 0xd9, 0x1d, 0x23, 0x2c,
0x36, 0x8a, 0x7b, 0xe5, 0x8a, 0x54, 0x68, 0xec, 0xe6, 0x08, 0x22, 0xd0, 0x16, 0xbc, 0x14, 0x64,
0x7d, 0x48, 0x32, 0x42, 0x16, 0x3f, 0x72, 0xa6, 0x21, 0xb1, 0x99, 0x9d, 0x67, 0x57, 0x21, 0x4e,
0xbe, 0x13, 0x6b, 0xd8, 0x38, 0x55, 0x9b, 0x98, 0x54, 0x82, 0xfb, 0x58, 0xd6, 0xac, 0x93, 0x0f,
0xd1, 0x8a, 0xef, 0xe8, 0x2d, 0xb4, 0xbb, 0x56, 0x3f, 0x1d, 0x40, 0x17, 0x93, 0xcf, 0x7e, 0xf5,
0xdb, 0xff, 0x0d, 0x01, 0x8a, 0x66, 0x4f, 0xb8, 0x85, 0x3d, 0x98, 0x91, 0xb0, 0xac, 0xf4, 0xcf,
0x6d, 0x2a, 0x41, 0x4d, 0x45, 0xd1, 0x6c, 0xd6, 0xa0, 0xfa, 0x65, 0x88, 0x3e, 0xe1, 0xff, 0xa0,
0x14, 0x68, 0x2b, 0xe8, 0xb6, 0x13, 0x97, 0xa8, 0xb1, 0x38, 0x8a, 0x39, 0xff, 0xe4, 0x84, 0xfe,
0x55, 0x80, 0xa5, 0x3d, 0x6c, 0xb1, 0x0e, 0x81, 0xfd, 0x3f, 0x43, 0x81, 0x96, 0x33, 0x53, 0xff,
0x13, 0x92, 0x29, 0xbe, 0xf2, 0xec, 0x47, 0xa9, 0x45, 0x58, 0x20, 0x32, 0xb8, 0x63, 0xa9, 0x4d,
0xd9, 0xc2, 0x0a, 0x9d, 0x1f, 0xa1, 0x64, 0xb6, 0x8d, 0xb3, 0x3d, 0x13, 0x1b, 0xf6, 0xff, 0x38,
0xa1, 0x36, 0xc4, 0x1c, 0x2f, 0x02, 0x67, 0x17, 0xc7, 0xcf, 0x4e, 0xa6, 0x15, 0x5f, 0x0a, 0x9a,
0x95, 0xac, 0x9a, 0x4e, 0x99, 0x6d, 0x63, 0xf4, 0x2f, 0x02, 0x24, 0x9d, 0xf9, 0xec, 0x86, 0x7f,
0xd0, 0xb4, 0x13, 0xfe, 0xf3, 0xca, 0xd5, 0x73, 0x16, 0x6f, 0x07, 0xcd, 0x7e, 0x11, 0x2d, 0x39,
0xb3, 0x67, 0xbb, 0x7c, 0xc2, 0x6f, 0x0a, 0x70, 0x91, 0x3d, 0xe6, 0x0d, 0x3b, 0xb2, 0x33, 0x66,
0xc2, 0x80, 0x8e, 0x66, 0xfa, 0xc6, 0x54, 0x4e, 0x8a, 0xd9, 0x20, 0x07, 0x57, 0xd2, 0x7e, 0x07,
0x1f, 0x08, 0x19, 0xf4, 0x4f, 0x90, 0x70, 0x02, 0xc5, 0x7a, 0x87, 0x41, 0x61, 0x9a, 0xf0, 0x89,
0xeb, 0x34, 0xe0, 0xc4, 0x4c, 0x90, 0x0f, 0x4b, 0x68, 0x71, 0xe0, 0x03, 0x6b, 0xc3, 0x7d, 0x4d,
0x80, 0x25, 0x56, 0xa5, 0xba, 0x5d, 0x78, 0x75, 0x9a, 0x00, 0xb9, 0x5b, 0x4d, 0xe9, 0xeb, 0x53,
0x38, 0x27, 0xde, 0x09, 0x72, 0x6c, 0x39, 0xed, 0x75, 0x8c, 0x84, 0xe6, 0xff, 0x05, 0x58, 0xf2,
0xf5, 0xd7, 0xc6, 0x25, 0x2f, 0xa8, 0x19, 0x17, 0xb8, 0xf9, 0xdf, 0x08, 0x72, 0xe8, 0xb2, 0xb8,
0xea, 0x71, 0x28, 0xcb, 0xba, 0x3d, 0x7d, 0xe2, 0xd8, 0xa7, 0x02, 0x6c, 0x48, 0xd8, 0xc4, 0x1d,
0xa5, 0xd4, 0x77, 0xf5, 0x2a, 0x9b, 0xb4, 0xc0, 0x2c, 0x8d, 0xcb, 0x61, 0x90, 0x23, 0xb9, 0x20,
0x47, 0xb6, 0xc4, 0xeb, 0x3e, 0x47, 0x0c, 0x3a, 0xf5, 0xa9, 0x6b, 0x4e, 0x2f, 0x90, 0x58, 0x3b,
0xef, 0x39, 0x81, 0xe4, 0x74, 0xc4, 0xa6, 0x04, 0x12, 0xeb, 0x8b, 0x79, 0x81, 0xc4, 0x5c, 0x98,
0x0a, 0x48, 0xee, 0x26, 0xd2, 0x24, 0x20, 0x51, 0xd9, 0x29, 0x81, 0x44, 0x1d, 0x23, 0xa1, 0xd1,
0x61, 0x49, 0xc2, 0x6d, 0xfd, 0x14, 0x4f, 0x13, 0x9d, 0xa0, 0x14, 0x05, 0x07, 0x23, 0xe3, 0x0b,
0xc6, 0xff, 0x79, 0x90, 0x3b, 0x31, 0x18, 0xa3, 0x3b, 0x6a, 0x2f, 0x88, 0x5b, 0xea, 0x4b, 0x10,
0x6e, 0x5d, 0x9d, 0x4a, 0x86, 0x21, 0xd6, 0xd7, 0xf9, 0x5c, 0x70, 0xcb, 0x1d, 0x19, 0x8d, 0xdb,
0xa1, 0xab, 0xc2, 0x6e, 0x10, 0x3d, 0xe7, 0x55, 0xe1, 0xea, 0x84, 0x4d, 0x79, 0x55, 0xf0, 0x8e,
0x09, 0xfa, 0xc4, 0xed, 0x85, 0xfd, 0x58, 0xb0, 0x35, 0xe9, 0x6d, 0xc0, 0x7e, 0xb2, 0x48, 0x5f,
0x9b, 0x28, 0x39, 0xa5, 0x3f, 0xf6, 0x5b, 0x83, 0xf7, 0xea, 0xb2, 0x03, 0x33, 0xd5, 0xd5, 0x35,
0xdc, 0xb6, 0x9a, 0x74, 0x75, 0xd9, 0x5d, 0xa1, 0xe9, 0xae, 0x2e, 0x1e, 0x30, 0x92, 0xb9, 0x53,
0x5e, 0x53, 0x94, 0x8e, 0xe5, 0xe0, 0x8c, 0xbd, 0x3c, 0x55, 0x8f, 0xc5, 0x14, 0x6f, 0x05, 0xcd,
0x9e, 0x44, 0x89, 0xc1, 0xec, 0x6d, 0x32, 0xd5, 0x7f, 0x0b, 0x90, 0xb4, 0x8f, 0x1a, 0xa7, 0x77,
0x34, 0x26, 0x57, 0xc3, 0x3d, 0xa9, 0x40, 0x2c, 0xdf, 0x0f, 0xf2, 0x60, 0x33, 0xbd, 0xee, 0xc2,
0x32, 0x37, 0x66, 0x66, 0xf9, 0x7f, 0xef, 0x92, 0x48, 0x7c, 0x47, 0x80, 0x0d, 0x1a, 0x8a, 0xc0,
0x47, 0x8e, 0xa0, 0xf0, 0xec, 0x4c, 0xe1, 0xb6, 0xc7, 0xd6, 0x18, 0x47, 0xd1, 0x95, 0x6c, 0x97,
0xc8, 0xa8, 0xd8, 0x74, 0x39, 0xda, 0x74, 0x0c, 0xa0, 0x8f, 0x20, 0x96, 0x53, 0x94, 0xd2, 0xb1,
0x5c, 0xa9, 0x57, 0x03, 0x7d, 0xda, 0x1a, 0xdb, 0xcc, 0x72, 0x35, 0xa0, 0xc6, 0x40, 0x46, 0x5c,
0x1a, 0x4a, 0x5a, 0x56, 0xb7, 0xba, 0x24, 0x50, 0x1f, 0x0b, 0xee, 0xa6, 0x5d, 0xbd, 0x8a, 0x5e,
0x9e, 0x78, 0x9b, 0xd3, 0x19, 0x03, 0x93, 0xf6, 0x37, 0x41, 0x1e, 0x5c, 0x49, 0xaf, 0xf9, 0x3c,
0x70, 0x9f, 0x85, 0x1a, 0xcc, 0xf3, 0x3b, 0x61, 0x7c, 0x30, 0x82, 0x26, 0x0e, 0xde, 0xce, 0x19,
0xff, 0xd2, 0xd1, 0xf7, 0x05, 0x58, 0xe2, 0x1f, 0x75, 0x7d, 0xe7, 0x23, 0x73, 0xec, 0xed, 0x38,
0xb2, 0x0b, 0x96, 0xbe, 0x7b, 0x0e, 0x0d, 0x9e, 0xa3, 0xd7, 0x83, 0x1c, 0x5d, 0x17, 0x57, 0xa8,
0xa3, 0x2d, 0xa2, 0x44, 0xbd, 0x6d, 0x98, 0x54, 0x95, 0x84, 0xe7, 0xa7, 0x02, 0x5c, 0xb4, 0x1d,
0x1e, 0x7c, 0xf0, 0x9a, 0xe8, 0xb5, 0xf3, 0x3c, 0xa4, 0xdb, 0x5e, 0xbf, 0x7e, 0x3e, 0x25, 0xee,
0x78, 0x30, 0xcc, 0xc5, 0xf5, 0x6c, 0x4b, 0xd3, 0x8f, 0x64, 0x8d, 0x14, 0xd2, 0x44, 0x59, 0x37,
0x5a, 0xa6, 0xdb, 0xfb, 0xff, 0x12, 0x60, 0x95, 0xee, 0xc7, 0x77, 0xd9, 0x94, 0xee, 0x17, 0xe9,
0xe7, 0xa8, 0x8a, 0x86, 0x9e, 0xb4, 0xc5, 0x9d, 0x20, 0xbf, 0xd6, 0xd0, 0x6a, 0xd6, 0xf5, 0xb2,
0x9d, 0xe5, 0xa6, 0xc8, 0xf7, 0xd0, 0xbf, 0xd9, 0x0e, 0xf1, 0xd5, 0xfe, 0x59, 0x1d, 0x1a, 0x5b,
0xa6, 0xb9, 0x1d, 0x6a, 0xe3, 0x87, 0x3f, 0x14, 0x3e, 0xcd, 0xfd, 0xbb, 0x80, 0xde, 0x84, 0x28,
0xf9, 0x14, 0xdf, 0xcc, 0x55, 0x8b, 0x62, 0x06, 0x6d, 0x9d, 0x58, 0x56, 0xd7, 0x7c, 0x90, 0xcd,
0xb6, 0x54, 0xeb, 0xa4, 0x77, 0xb4, 0xdd, 0xd4, 0xdb, 0x59, 0x32, 0xb7, 0xb3, 0x82, 0xee, 0xfb,
0xad, 0x2c, 0x31, 0xbf, 0x13, 0x7e, 0x75, 0xfb, 0x6e, 0x46, 0x08, 0xed, 0x24, 0xe5, 0x6e, 0x57,
0xe3, 0x97, 0x78, 0xf6, 0x3d, 0x53, 0xef, 0x0c, 0x53, 0x5a, 0x46, 0xb7, 0xf9, 0xc0, 0x27, 0xf3,
0xc0, 0x27, 0xf3, 0xee, 0x8d, 0x71, 0x33, 0x12, 0x09, 0x3a, 0xed, 0xd1, 0x2c, 0x0d, 0xcd, 0x6b,
0x7f, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x86, 0x9f, 0x6d, 0x7d, 0xe5, 0x34, 0x00, 0x00,
// 3616 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x5f, 0x6f, 0x1b, 0x57,
0x76, 0xf7, 0x90, 0x94, 0x44, 0x1e, 0x4a, 0x14, 0x75, 0x2d, 0x4b, 0x14, 0x65, 0xd9, 0xf4, 0x38,
0x8e, 0x65, 0xc6, 0x16, 0x6d, 0x25, 0x41, 0x6d, 0x07, 0x48, 0x40, 0x8b, 0xb4, 0xc4, 0x5a, 0xfc,
0x93, 0x21, 0xe5, 0xd4, 0x01, 0x0a, 0x62, 0xc4, 0xb9, 0xa2, 0x26, 0x19, 0x72, 0x98, 0x99, 0xa1,
0x54, 0x06, 0x68, 0x80, 0xa6, 0x45, 0xd3, 0x02, 0x4d, 0x5b, 0xa4, 0x45, 0x81, 0xa2, 0xe8, 0x43,
0x81, 0xb6, 0xe8, 0x43, 0xd1, 0x3e, 0x14, 0x2d, 0x50, 0xb4, 0x1f, 0xa0, 0x2f, 0x7d, 0x58, 0x2c,
0xb0, 0x1f, 0x60, 0xb1, 0x5f, 0x61, 0xb1, 0xd8, 0xec, 0xcb, 0xe2, 0xfe, 0x99, 0xe1, 0x70, 0x86,
0x43, 0x52, 0xf6, 0x66, 0x37, 0x08, 0xf2, 0x24, 0xde, 0xf3, 0xef, 0xfe, 0xee, 0x39, 0xe7, 0xde,
0x7b, 0xe6, 0x1e, 0x01, 0xc8, 0x7d, 0xeb, 0x74, 0xa7, 0x67, 0xe8, 0x96, 0x8e, 0x52, 0x2d, 0x59,
0x37, 0x77, 0x3e, 0x55, 0x2d, 0x59, 0xc1, 0xda, 0x0e, 0x65, 0xc8, 0x3d, 0x75, 0xe7, 0xec, 0x41,
0xfa, 0x6a, 0x5b, 0xd7, 0xdb, 0x1a, 0xce, 0xc9, 0x3d, 0x35, 0x27, 0x77, 0xbb, 0xba, 0x25, 0x5b,
0xaa, 0xde, 0x35, 0x99, 0x5e, 0x7a, 0x93, 0x73, 0xe9, 0xe8, 0xb8, 0x7f, 0x92, 0xc3, 0x9d, 0x9e,
0x35, 0xe0, 0xcc, 0xab, 0x5e, 0xa6, 0x69, 0x19, 0xfd, 0x96, 0xc5, 0xb9, 0xd7, 0xbd, 0x5c, 0x4b,
0xed, 0x60, 0xd3, 0x92, 0x3b, 0x3d, 0x2e, 0xb0, 0x7e, 0x26, 0x6b, 0xaa, 0x22, 0x5b, 0x38, 0x67,
0xff, 0xe0, 0x8c, 0xbb, 0xf4, 0x4f, 0xeb, 0x5e, 0x1b, 0x77, 0xef, 0x99, 0xe7, 0x72, 0xbb, 0x8d,
0x8d, 0x9c, 0xde, 0xa3, 0xb0, 0xc6, 0x40, 0x4c, 0x91, 0xd5, 0x30, 0xb6, 0x2d, 0xc5, 0x39, 0x97,
0xe9, 0x9f, 0x5c, 0x07, 0x9b, 0xa6, 0xdc, 0xe6, 0xc6, 0xc5, 0x63, 0x48, 0x1e, 0x99, 0xd8, 0xa8,
0x63, 0xd3, 0x54, 0xf5, 0xee, 0x73, 0x15, 0x9f, 0x9b, 0xa8, 0x02, 0x4b, 0x7d, 0x13, 0x1b, 0x4d,
0x93, 0x11, 0xcd, 0x94, 0x90, 0x09, 0x6f, 0xc7, 0x77, 0xef, 0xec, 0x04, 0x79, 0x6d, 0xc7, 0x63,
0x42, 0x5a, 0xec, 0x0f, 0x09, 0xa6, 0xf8, 0x77, 0x21, 0x58, 0xf6, 0x48, 0xa0, 0x04, 0x84, 0x54,
0x25, 0x25, 0x64, 0x84, 0xed, 0x98, 0x14, 0x52, 0x15, 0xb4, 0x01, 0x51, 0xb9, 0x8d, 0xbb, 0x56,
0x53, 0x55, 0x52, 0x21, 0x4a, 0x5d, 0xa0, 0xe3, 0x92, 0x82, 0x4a, 0x2c, 0x74, 0x4d, 0xd3, 0x92,
0x2d, 0x9c, 0x0a, 0x67, 0x84, 0xed, 0xc4, 0x6e, 0x76, 0x26, 0x2c, 0x75, 0xa2, 0x21, 0xc5, 0x08,
0x97, 0xfe, 0x44, 0xeb, 0xb0, 0x40, 0x57, 0xa6, 0x2a, 0xa9, 0x08, 0x9d, 0x64, 0x9e, 0x0c, 0x4b,
0x0a, 0xda, 0x84, 0x18, 0x65, 0x74, 0xe5, 0x0e, 0x4e, 0xcd, 0x51, 0x56, 0x94, 0x10, 0x2a, 0x72,
0x07, 0xa3, 0x34, 0x44, 0x4d, 0xfc, 0x49, 0x1f, 0x77, 0x5b, 0x38, 0x35, 0x9f, 0x11, 0xb6, 0x23,
0x92, 0x33, 0x46, 0x5b, 0x00, 0x9a, 0xde, 0x56, 0xbb, 0x4c, 0x73, 0x81, 0x6a, 0xc6, 0x28, 0x85,
0xaa, 0xde, 0x80, 0x45, 0x45, 0x35, 0x7b, 0x9a, 0x3c, 0x60, 0x02, 0x51, 0x2a, 0x10, 0xe7, 0x34,
0x22, 0x22, 0x7e, 0x11, 0x85, 0x28, 0xc1, 0x3c, 0xd6, 0x2d, 0x8f, 0x60, 0x8e, 0x2d, 0x3b, 0x44,
0x97, 0x7d, 0x73, 0xca, 0xb2, 0xe9, 0x7a, 0x99, 0x06, 0x7a, 0x0f, 0x96, 0x5a, 0x06, 0xa6, 0xb9,
0xd1, 0x54, 0x6c, 0xcf, 0xc5, 0x77, 0xd3, 0x3b, 0x2c, 0x11, 0x77, 0xec, 0x44, 0xdc, 0x69, 0xd8,
0x89, 0x28, 0x2d, 0xda, 0x0a, 0x05, 0x62, 0xe0, 0x1d, 0x88, 0xb7, 0x4e, 0xe5, 0x6e, 0x1b, 0x33,
0xf5, 0xc8, 0x54, 0x75, 0x60, 0xe2, 0x54, 0xf9, 0x11, 0x80, 0x26, 0x9b, 0x56, 0x93, 0xba, 0x82,
0x7a, 0x74, 0xb2, 0x6e, 0x8c, 0x48, 0x1f, 0x12, 0x61, 0x54, 0x84, 0x64, 0x4f, 0x36, 0xcd, 0x73,
0xdd, 0x50, 0x9a, 0xcc, 0xa2, 0x42, 0xdd, 0x3e, 0xd9, 0xc0, 0xb2, 0xad, 0xb3, 0xc7, 0x54, 0x46,
0x43, 0xba, 0xe0, 0x09, 0xe9, 0x16, 0xc0, 0x89, 0x6a, 0x98, 0x96, 0x3b, 0x2a, 0x31, 0x4a, 0xa1,
0xec, 0x4d, 0xa0, 0x78, 0x18, 0x37, 0xc6, 0x74, 0x09, 0x61, 0x6c, 0x4c, 0xc1, 0x17, 0x53, 0xa2,
0xdf, 0x55, 0x5b, 0x1f, 0x33, 0x7e, 0x9c, 0xe9, 0x13, 0x02, 0x65, 0xde, 0x03, 0xd4, 0x33, 0xf0,
0x09, 0x36, 0x0c, 0xac, 0x34, 0x35, 0xb9, 0xdb, 0xee, 0xcb, 0x6d, 0x9c, 0x5a, 0xa4, 0x52, 0x2b,
0x0e, 0xe7, 0x90, 0x33, 0xd0, 0x43, 0x98, 0x6f, 0xe3, 0xae, 0x82, 0x8d, 0xd4, 0x12, 0xcd, 0x81,
0x4c, 0x70, 0x0e, 0xec, 0x53, 0x39, 0x89, 0xcb, 0xa3, 0x55, 0x98, 0xc3, 0x1d, 0x59, 0xd5, 0x52,
0x09, 0x6a, 0x9b, 0x0d, 0x50, 0x16, 0x56, 0x54, 0xb3, 0x49, 0x7f, 0x37, 0xcf, 0xb0, 0xa1, 0x9e,
0xa8, 0x58, 0x49, 0x2d, 0x67, 0x84, 0xed, 0xa8, 0xb4, 0xac, 0x9a, 0x45, 0x42, 0x7f, 0xce, 0xc9,
0xc4, 0x42, 0xef, 0x54, 0xef, 0xe2, 0x54, 0x92, 0x59, 0xa0, 0x03, 0x6e, 0x81, 0xfe, 0x1e, 0x5a,
0x58, 0xb1, 0x2d, 0xd4, 0x08, 0xdd, 0xb1, 0x90, 0x82, 0x85, 0x96, 0xde, 0xef, 0x5a, 0xc6, 0x20,
0x85, 0xd8, 0xb6, 0xe6, 0x43, 0xb2, 0xab, 0x34, 0xbd, 0x25, 0x6b, 0xaa, 0x35, 0x48, 0x5d, 0xe6,
0x2e, 0xe6, 0x63, 0x74, 0x1d, 0xe2, 0x3d, 0xdd, 0xb4, 0x64, 0xad, 0xd9, 0xd2, 0x15, 0x9c, 0x5a,
0xa5, 0x6c, 0x60, 0xa4, 0x3d, 0x5d, 0xc1, 0x68, 0x0d, 0xe6, 0x0d, 0xdc, 0x56, 0xf5, 0x6e, 0xea,
0x0a, 0xdb, 0xc7, 0x6c, 0x84, 0x6e, 0x41, 0xc2, 0xb4, 0x0c, 0x8c, 0xad, 0xa6, 0xac, 0x28, 0x06,
0x36, 0xcd, 0xd4, 0x1a, 0xe5, 0x2f, 0x31, 0x6a, 0x9e, 0x11, 0x47, 0x76, 0xf4, 0xba, 0x67, 0x47,
0xdf, 0x82, 0x84, 0x81, 0x4d, 0xbd, 0x6f, 0xb4, 0x70, 0x53, 0x3f, 0xef, 0x62, 0x23, 0x95, 0x62,
0x26, 0x6c, 0x6a, 0x95, 0x10, 0x09, 0xc4, 0xe1, 0xc6, 0x37, 0x53, 0x1b, 0x99, 0x30, 0x81, 0xe8,
0xec, 0x7c, 0x13, 0xdd, 0x87, 0x55, 0x57, 0x98, 0x87, 0x67, 0x44, 0x9a, 0x5a, 0x1b, 0xa6, 0xc0,
0xa1, 0xad, 0x22, 0xfe, 0x77, 0x18, 0xe2, 0x64, 0x1b, 0xd7, 0x0c, 0xfd, 0x44, 0xd5, 0xb0, 0xef,
0x30, 0x18, 0xc9, 0xe8, 0xd0, 0xc4, 0x8c, 0x0e, 0x4f, 0xcc, 0xe8, 0x88, 0x27, 0xa3, 0x47, 0xd2,
0x75, 0xce, 0x93, 0xae, 0xde, 0x74, 0x9f, 0xf7, 0xa7, 0xfb, 0xf8, 0x8c, 0x5e, 0x98, 0x9e, 0xd1,
0xd1, 0x0b, 0x66, 0xb4, 0x3b, 0x6e, 0x31, 0x4f, 0xdc, 0x7c, 0xe7, 0x1d, 0xbc, 0xda, 0x79, 0x17,
0xbf, 0xc8, 0x79, 0x27, 0xfe, 0x65, 0x84, 0xdd, 0x71, 0x3c, 0x76, 0x63, 0x0f, 0xf3, 0xef, 0xe3,
0xf7, 0xad, 0x8d, 0x9f, 0x77, 0x3b, 0x2f, 0xce, 0xbc, 0x9d, 0x97, 0x02, 0xb7, 0xf3, 0x9f, 0x85,
0x20, 0x75, 0xd4, 0x23, 0x58, 0x5c, 0x89, 0x21, 0x91, 0xe5, 0x9a, 0x16, 0xba, 0x33, 0x12, 0x6e,
0x9a, 0x23, 0x4f, 0xe0, 0xeb, 0x27, 0x0b, 0xc6, 0x5c, 0x52, 0x48, 0xfd, 0x9f, 0xe0, 0x0e, 0xfd,
0x6d, 0x77, 0xe8, 0x43, 0x3e, 0xc9, 0x61, 0x1a, 0xdc, 0x76, 0xa7, 0x41, 0xd8, 0x2f, 0xe8, 0xa4,
0xc4, 0xa3, 0xb1, 0xf1, 0x8e, 0xf8, 0x34, 0x26, 0xc6, 0x7e, 0xee, 0x62, 0xb1, 0x17, 0xdf, 0x85,
0x2b, 0xec, 0x6a, 0x3e, 0xe2, 0x29, 0x6f, 0xbb, 0xe2, 0x96, 0x7b, 0x5b, 0x30, 0x4f, 0x44, 0xbf,
0x7e, 0x32, 0x67, 0x84, 0x29, 0x68, 0x7b, 0x83, 0x88, 0x3f, 0x15, 0x20, 0x46, 0x54, 0xe9, 0x0d,
0xe5, 0xdb, 0x5b, 0xce, 0x5d, 0x17, 0x72, 0xdf, 0x75, 0xdb, 0xe0, 0xbd, 0xd2, 0xa8, 0x5f, 0xc6,
0xdc, 0x74, 0xee, 0xcc, 0x8c, 0x4c, 0xcb, 0xcc, 0xb9, 0x57, 0xcb, 0xcc, 0xf9, 0x0b, 0x9d, 0x2c,
0x3f, 0x17, 0x60, 0xc9, 0x59, 0xf7, 0xd8, 0x73, 0xe5, 0xbb, 0xbb, 0xf6, 0xc7, 0x90, 0xa2, 0x28,
0x07, 0xe5, 0x81, 0xe3, 0x02, 0x3b, 0x6d, 0xae, 0x41, 0x84, 0x16, 0x07, 0xfe, 0xbd, 0x43, 0xe9,
0xe2, 0x01, 0xac, 0x31, 0x5d, 0x9f, 0xa6, 0xd7, 0x7f, 0xb6, 0xa5, 0x50, 0x80, 0xa5, 0xc7, 0xb0,
0x36, 0xdc, 0xc7, 0x23, 0x96, 0x32, 0xb6, 0xe7, 0xfd, 0x20, 0x18, 0x43, 0xfc, 0x19, 0xcf, 0x5a,
0x5a, 0x15, 0x8d, 0x8b, 0x1c, 0xab, 0xaf, 0x42, 0x53, 0xeb, 0xab, 0xf0, 0xf8, 0xfa, 0xea, 0xdb,
0x1b, 0xbb, 0x5f, 0xf0, 0xbc, 0x65, 0x78, 0x03, 0xf2, 0xf6, 0x3b, 0xbb, 0xfa, 0x47, 0xee, 0x9c,
0xa1, 0xa0, 0xed, 0x9c, 0xb9, 0x6e, 0xaf, 0x9a, 0xe5, 0x4c, 0xec, 0xeb, 0x27, 0xf3, 0x46, 0x24,
0x29, 0xa4, 0x56, 0xb9, 0x03, 0xc4, 0x87, 0xee, 0xc4, 0x1d, 0x51, 0x9d, 0x96, 0xf2, 0xff, 0x1f,
0x62, 0x05, 0xa4, 0x5d, 0xe6, 0x7a, 0x1d, 0xee, 0x2a, 0xc6, 0x43, 0xc1, 0xc5, 0x78, 0x78, 0x72,
0x31, 0x1e, 0x99, 0x50, 0x8c, 0xcf, 0x4d, 0x29, 0xc6, 0xe7, 0xa7, 0x15, 0xe3, 0x0b, 0xd3, 0x82,
0x18, 0x7d, 0xb5, 0x20, 0xc6, 0x2e, 0x14, 0xc4, 0x1f, 0xf0, 0x87, 0x0b, 0x8e, 0x74, 0x6c, 0x12,
0x7f, 0xef, 0xd3, 0x8b, 0xf9, 0xf4, 0xc7, 0x82, 0xbb, 0x2a, 0xe2, 0x78, 0xed, 0x04, 0x17, 0x87,
0xce, 0xf4, 0x16, 0x02, 0x8e, 0x5b, 0x5f, 0x73, 0xb9, 0x35, 0xe4, 0xad, 0x16, 0x1c, 0x07, 0xdf,
0x19, 0x75, 0x70, 0xd8, 0x23, 0xe8, 0x76, 0x75, 0xc6, 0x71, 0x75, 0xc4, 0x23, 0x65, 0x3b, 0x3d,
0xe7, 0x73, 0xfa, 0x9c, 0x47, 0x72, 0xd4, 0xfd, 0xe2, 0x55, 0x80, 0x1a, 0x7f, 0x8e, 0x28, 0x15,
0xbc, 0x29, 0x23, 0x3e, 0x84, 0x65, 0x9b, 0x3b, 0xac, 0x81, 0xa2, 0xf6, 0xfb, 0x85, 0xf7, 0x5c,
0x38, 0x90, 0x1c, 0x96, 0xa8, 0x41, 0xa2, 0x36, 0xf2, 0xcc, 0x81, 0xee, 0xc2, 0xa2, 0xae, 0x29,
0xcd, 0x60, 0xe5, 0xb8, 0xae, 0x29, 0xb6, 0x0e, 0x91, 0xee, 0xe2, 0xf3, 0xa1, 0x74, 0xc8, 0x27,
0xdd, 0xc5, 0xe7, 0xb6, 0xb4, 0x28, 0xc2, 0x22, 0xbf, 0x7d, 0x4f, 0xe4, 0xaa, 0xd5, 0x43, 0xc8,
0x7d, 0xfc, 0xf0, 0x23, 0xa7, 0x04, 0x8b, 0xe5, 0xbe, 0x66, 0xa9, 0x4f, 0xe5, 0x96, 0xa5, 0x1b,
0x26, 0x7a, 0x04, 0x91, 0xce, 0x89, 0x6c, 0x3f, 0x19, 0xde, 0x0a, 0xae, 0x0e, 0x5d, 0x5a, 0x12,
0x55, 0x11, 0x3f, 0x83, 0xb8, 0x8b, 0x88, 0xde, 0x86, 0x88, 0x35, 0xe8, 0xb1, 0xd9, 0x12, 0xbb,
0x37, 0x26, 0x58, 0x3a, 0x91, 0x1b, 0x83, 0x1e, 0x96, 0xa8, 0x38, 0x7a, 0x38, 0xfa, 0x62, 0x26,
0x4e, 0xd0, 0x7b, 0x9a, 0x77, 0x3f, 0x98, 0x89, 0x5f, 0x0a, 0x90, 0x60, 0x2b, 0x95, 0xb0, 0xd9,
0xd3, 0xbb, 0xe6, 0xc8, 0x7b, 0xa1, 0x30, 0xf2, 0x5e, 0x98, 0x84, 0x70, 0xdf, 0xb0, 0x0b, 0x2e,
0xf2, 0x93, 0x6c, 0x58, 0x13, 0xb7, 0x0c, 0x6c, 0xf1, 0xbd, 0xce, 0x47, 0x43, 0x3c, 0x91, 0x8b,
0xe2, 0x91, 0x20, 0x51, 0x2d, 0x15, 0xf6, 0xf6, 0x34, 0x15, 0x77, 0xad, 0x7c, 0xdf, 0x3a, 0x25,
0xdf, 0x79, 0x2d, 0x3a, 0x1a, 0x02, 0x8a, 0x32, 0x42, 0x49, 0x41, 0x37, 0x61, 0x89, 0x33, 0x39,
0x0e, 0x06, 0x6e, 0x91, 0x11, 0xeb, 0x94, 0x26, 0xfe, 0x41, 0x08, 0xd6, 0xc8, 0xbe, 0xdb, 0x37,
0x64, 0x42, 0x93, 0x8d, 0xd6, 0xa9, 0x9d, 0x82, 0x6b, 0x30, 0xaf, 0x9f, 0x9c, 0x98, 0xd8, 0xa2,
0x96, 0x23, 0x12, 0x1f, 0x91, 0x5b, 0x5a, 0x53, 0x3b, 0x2a, 0xb3, 0x17, 0x91, 0xd8, 0x00, 0xfd,
0x2e, 0x24, 0x4c, 0xdd, 0xb0, 0xd4, 0x6e, 0xbb, 0xd9, 0xd2, 0xb5, 0x7e, 0xa7, 0xcb, 0x1f, 0x66,
0xef, 0x4e, 0x7e, 0xa1, 0x74, 0xcd, 0xfb, 0x0c, 0x0f, 0xe8, 0x06, 0xfa, 0x5c, 0x08, 0x65, 0x2e,
0x49, 0x4b, 0xdc, 0xda, 0x1e, 0x35, 0x46, 0xfc, 0x2b, 0x9b, 0x2d, 0xea, 0xb3, 0xa8, 0x44, 0x7e,
0xa2, 0x03, 0x58, 0xf8, 0xa4, 0x8f, 0x0d, 0x15, 0x93, 0xcd, 0x47, 0x72, 0x6b, 0x67, 0xe6, 0x99,
0xde, 0xef, 0x63, 0x63, 0x20, 0xd9, 0xea, 0xe2, 0x7f, 0x09, 0xb0, 0x3a, 0x4e, 0x02, 0x1d, 0x40,
0xf8, 0x63, 0x3c, 0xe0, 0x09, 0xf7, 0xb2, 0x0b, 0x21, 0x26, 0xd0, 0xbb, 0x30, 0xdf, 0xc1, 0xd6,
0xa9, 0xae, 0xf0, 0x2c, 0x7c, 0x3d, 0xd8, 0x18, 0xb3, 0x51, 0xa6, 0xd2, 0x12, 0xd7, 0x22, 0x3e,
0x3f, 0x93, 0xb5, 0xbe, 0xfd, 0x0e, 0xc0, 0x06, 0xe2, 0xdf, 0x87, 0x60, 0xdd, 0x17, 0x3c, 0x9e,
0xa9, 0x17, 0x8b, 0xde, 0x0d, 0x58, 0xb4, 0x74, 0x72, 0x38, 0x1a, 0xd8, 0xec, 0x6b, 0x2c, 0x65,
0x23, 0x52, 0x9c, 0xd2, 0x24, 0x4a, 0x42, 0xef, 0x91, 0x53, 0x91, 0x32, 0x23, 0xd4, 0xdd, 0xb7,
0x67, 0xf0, 0x07, 0x7d, 0xfb, 0xe7, 0x6a, 0xec, 0x51, 0x41, 0x6f, 0x61, 0xd3, 0xc4, 0x4a, 0xd3,
0xb9, 0x8c, 0xe6, 0xe8, 0x4c, 0x2b, 0x0e, 0xa7, 0x6e, 0xdf, 0x4a, 0x79, 0x48, 0x9c, 0xa9, 0xf8,
0xbc, 0xe9, 0xb4, 0x45, 0x66, 0x28, 0xb8, 0x96, 0x88, 0x86, 0x33, 0x14, 0xff, 0x89, 0x57, 0x9c,
0x0e, 0x16, 0xb2, 0xfa, 0xaa, 0xd1, 0x2e, 0xd9, 0x9b, 0x85, 0x0d, 0xd0, 0x55, 0x88, 0xd5, 0x0c,
0xfd, 0x23, 0xdc, 0xb2, 0x4a, 0x76, 0xb3, 0x61, 0x48, 0x20, 0x9e, 0x3c, 0xa2, 0x9b, 0xdc, 0xde,
0xc8, 0x6c, 0x44, 0x6c, 0x49, 0xba, 0x86, 0x4d, 0xea, 0x8f, 0x98, 0xc4, 0x06, 0xe4, 0xfa, 0xaf,
0x1a, 0xed, 0xca, 0xf0, 0xe1, 0xc5, 0x1e, 0x12, 0x0e, 0x05, 0x52, 0x52, 0xf8, 0x15, 0x6d, 0x0f,
0xc5, 0x7f, 0x11, 0x60, 0xa3, 0x3c, 0xe0, 0x33, 0x56, 0x8d, 0xf6, 0xab, 0xec, 0x43, 0xff, 0x46,
0x79, 0xe6, 0xdd, 0x28, 0x0f, 0x26, 0x1c, 0x39, 0x3e, 0x14, 0x9e, 0xbd, 0xf2, 0xbf, 0x02, 0xac,
0x07, 0x08, 0xa1, 0x67, 0xee, 0xed, 0x92, 0xbb, 0xc8, 0x24, 0xbf, 0xb6, 0x1d, 0xf3, 0x8f, 0x02,
0xa4, 0xc7, 0x79, 0xfa, 0x9b, 0xda, 0x34, 0x6f, 0x7b, 0x36, 0xcd, 0x56, 0xf0, 0x2a, 0xaa, 0x46,
0xdb, 0xde, 0x2a, 0xe2, 0x1d, 0x08, 0x57, 0x8d, 0xb6, 0xaf, 0xb4, 0x44, 0x10, 0x71, 0x3d, 0x15,
0xd2, 0xdf, 0xe2, 0x03, 0x58, 0x2a, 0x0f, 0x6a, 0xd8, 0xe8, 0xa8, 0xac, 0xb9, 0x86, 0x32, 0x10,
0xef, 0x0d, 0x87, 0xf4, 0xde, 0x8d, 0x49, 0x6e, 0x92, 0x28, 0x43, 0x82, 0x15, 0x0b, 0x4e, 0x99,
0xe5, 0xac, 0x4f, 0x70, 0xaf, 0xef, 0x36, 0x2c, 0xdb, 0xdb, 0xb4, 0xc9, 0xdd, 0xc2, 0xd6, 0x9f,
0xb0, 0xc9, 0x55, 0xe6, 0x1e, 0x9e, 0x73, 0x61, 0x27, 0xe7, 0x44, 0x13, 0x16, 0xf8, 0x14, 0xe8,
0x31, 0x2c, 0xb0, 0x6a, 0xcf, 0xae, 0x01, 0x26, 0xbc, 0x10, 0x31, 0x1d, 0xc9, 0x56, 0x70, 0xc5,
0x23, 0x34, 0x3e, 0x1e, 0x61, 0x17, 0x5e, 0xf1, 0x4f, 0x43, 0x30, 0xcf, 0xab, 0x20, 0x4f, 0x45,
0x2a, 0x5c, 0xe8, 0xe9, 0xaf, 0x00, 0x80, 0xcf, 0xc8, 0xbd, 0x49, 0xcb, 0x8d, 0x10, 0xd5, 0xf5,
0x16, 0x2e, 0x0c, 0xef, 0x21, 0xad, 0x2e, 0x3f, 0xc5, 0x4a, 0x99, 0xf5, 0x50, 0xa5, 0x18, 0x55,
0x24, 0xd5, 0xc7, 0x48, 0xc5, 0x1d, 0xf6, 0x54, 0xdc, 0x9b, 0x10, 0xc3, 0x8a, 0x6a, 0xe9, 0xae,
0xc6, 0x63, 0x94, 0x11, 0xd8, 0x79, 0xc3, 0x7e, 0xdb, 0x95, 0x3e, 0x1b, 0xa1, 0x37, 0x20, 0xa2,
0xc8, 0x96, 0xcc, 0x8f, 0xc1, 0x75, 0xdf, 0x62, 0xea, 0xb4, 0xbb, 0x2c, 0x51, 0x21, 0xf1, 0x5f,
0xc3, 0x90, 0x72, 0x2a, 0x43, 0xbd, 0xd3, 0xd3, 0xf0, 0xef, 0xa9, 0xd6, 0xa0, 0xa6, 0x6b, 0x6a,
0x6b, 0xe0, 0xcb, 0xab, 0x0c, 0xc4, 0x15, 0x6c, 0xb6, 0x0c, 0x95, 0xb6, 0x87, 0x79, 0x7a, 0xb9,
0x49, 0xbf, 0xe1, 0xde, 0xe1, 0x16, 0x40, 0x47, 0xed, 0x36, 0x35, 0xdc, 0x6d, 0x5b, 0xa7, 0xfc,
0xc6, 0x88, 0x75, 0xd4, 0xee, 0x21, 0x25, 0x90, 0x42, 0xe7, 0x54, 0x36, 0x9b, 0x9a, 0x7e, 0x8e,
0x8d, 0x96, 0x6c, 0xb2, 0x2f, 0xf3, 0xa8, 0xb4, 0x78, 0x2a, 0x9b, 0x87, 0x36, 0xcd, 0x16, 0xea,
0xf7, 0x7a, 0x5c, 0x68, 0xc1, 0x11, 0x3a, 0xb2, 0x69, 0x64, 0x22, 0x22, 0xd4, 0xed, 0x77, 0x8e,
0xf9, 0x63, 0x76, 0x54, 0x8a, 0x9d, 0xca, 0x66, 0x85, 0x12, 0x6c, 0xb6, 0x39, 0xe8, 0x1c, 0xeb,
0x1a, 0xfd, 0xcc, 0x61, 0xec, 0x3a, 0x25, 0x8c, 0x44, 0x1c, 0xfc, 0x6d, 0x61, 0xd5, 0x6c, 0x2a,
0xf8, 0x44, 0x26, 0x87, 0x41, 0x9c, 0xa9, 0xaa, 0x66, 0x81, 0x11, 0xb2, 0xc6, 0x48, 0xd7, 0x9d,
0xf5, 0xa6, 0x33, 0x70, 0xf5, 0xa8, 0x5e, 0x94, 0xea, 0xc5, 0x7a, 0xbd, 0x54, 0xad, 0xd4, 0x1b,
0xf9, 0x46, 0xb1, 0x79, 0x54, 0xa9, 0xd7, 0x8a, 0x7b, 0xa5, 0xa7, 0xa5, 0x62, 0x21, 0x79, 0x09,
0x6d, 0xc2, 0xba, 0x4f, 0x22, 0xbf, 0xd7, 0x28, 0x3d, 0x2f, 0x26, 0x05, 0x74, 0x1d, 0x36, 0x7d,
0xcc, 0x46, 0x51, 0x2a, 0x97, 0x2a, 0xf9, 0x46, 0xb1, 0x90, 0x0c, 0x65, 0x3f, 0x81, 0x24, 0x29,
0x27, 0xed, 0xc3, 0x8f, 0x26, 0xed, 0x06, 0x5c, 0xa1, 0xb4, 0x62, 0xbd, 0x56, 0xad, 0xd4, 0x8b,
0x8d, 0x17, 0xb5, 0x62, 0x73, 0xaf, 0x5a, 0x28, 0x26, 0x2f, 0xa1, 0x2d, 0xd8, 0xf0, 0xb1, 0x4a,
0x85, 0x66, 0xa3, 0xfa, 0xac, 0x58, 0x49, 0x0a, 0xe8, 0x26, 0x5c, 0x0f, 0x64, 0x73, 0xa1, 0x50,
0xf6, 0xdf, 0xf9, 0xe3, 0x17, 0x5b, 0xe0, 0x06, 0x5c, 0xa1, 0x08, 0xc7, 0xac, 0x6c, 0x15, 0x92,
0x43, 0x96, 0xb3, 0xa4, 0x35, 0x40, 0x43, 0x6a, 0xa9, 0xc2, 0xe9, 0x21, 0x74, 0x05, 0x56, 0x86,
0xf4, 0x42, 0xf1, 0xb0, 0x48, 0x16, 0x18, 0x1e, 0x35, 0x72, 0x58, 0xdd, 0x7b, 0x56, 0x2c, 0x24,
0x23, 0xa3, 0xc2, 0xf5, 0xa3, 0x7a, 0xad, 0x58, 0x29, 0x24, 0xe7, 0x46, 0xc9, 0xa5, 0x4a, 0xa9,
0x51, 0xca, 0x1f, 0x26, 0xe7, 0xb3, 0xbf, 0x03, 0xf3, 0xec, 0xd9, 0x9a, 0x4c, 0xbe, 0x5f, 0xac,
0x14, 0x8a, 0x92, 0x07, 0xea, 0x0a, 0x2c, 0x71, 0xfa, 0xd3, 0x62, 0x39, 0x7f, 0x48, 0x70, 0x2e,
0x43, 0x9c, 0x93, 0x28, 0x21, 0x84, 0x10, 0x24, 0x38, 0xa1, 0x50, 0x7a, 0x4e, 0x62, 0x92, 0x0c,
0x67, 0x0b, 0xb0, 0xc0, 0x3f, 0x54, 0xd0, 0x3a, 0x5c, 0x2e, 0x3f, 0xcd, 0x53, 0x97, 0x8d, 0xda,
0x5e, 0x86, 0xb8, 0xcd, 0xa8, 0x97, 0xeb, 0xcc, 0xb2, 0x4d, 0xa8, 0x36, 0x6a, 0xc9, 0x50, 0xf6,
0x04, 0xa2, 0xf6, 0x67, 0x02, 0x4a, 0xc1, 0x2a, 0xf9, 0x3d, 0xc6, 0x9d, 0x6b, 0x80, 0x1c, 0x4e,
0xa5, 0xda, 0x68, 0x4a, 0xc5, 0x7c, 0xe1, 0x45, 0x52, 0x20, 0xb8, 0x1c, 0x3a, 0xa3, 0x85, 0x88,
0xd7, 0x5c, 0xb4, 0x72, 0xf5, 0x39, 0xf1, 0x65, 0xf6, 0x0c, 0x90, 0xbf, 0xca, 0x45, 0xd7, 0x20,
0xed, 0xa7, 0x36, 0x8f, 0x2a, 0xcf, 0x2a, 0xd5, 0x0f, 0x2a, 0x2c, 0x67, 0xc6, 0xf0, 0xab, 0xd2,
0x7e, 0xb3, 0x54, 0x48, 0x0a, 0xe8, 0x06, 0x6c, 0x8d, 0x61, 0xd7, 0xa4, 0xea, 0x6f, 0x17, 0xf7,
0x1a, 0x44, 0x24, 0x94, 0x3d, 0x86, 0x2b, 0x63, 0xcb, 0x05, 0x74, 0x0b, 0x6e, 0x94, 0x5f, 0x70,
0xd1, 0xaa, 0xb4, 0x5f, 0x2f, 0xe6, 0xa5, 0xbd, 0x83, 0x67, 0xc5, 0x17, 0x9e, 0x95, 0x8b, 0x70,
0x6d, 0xbc, 0x18, 0x01, 0x51, 0xc9, 0x97, 0x8b, 0x49, 0x21, 0xfb, 0x23, 0x01, 0x16, 0xdd, 0x35,
0x04, 0x89, 0x07, 0x13, 0x2c, 0x17, 0x1b, 0x07, 0xd5, 0x42, 0xb3, 0xf8, 0xfe, 0x51, 0xfe, 0xb0,
0x9e, 0xbc, 0x84, 0xae, 0x42, 0x6a, 0x84, 0x51, 0x6f, 0xe4, 0xa5, 0x46, 0xbd, 0xf9, 0x41, 0xa9,
0x71, 0x90, 0x14, 0x48, 0x3e, 0x8f, 0x70, 0xf7, 0xaa, 0x95, 0x46, 0xbe, 0x54, 0xa9, 0x27, 0x43,
0x64, 0x77, 0x8c, 0xb1, 0xd8, 0x2c, 0xed, 0x57, 0xaa, 0x52, 0xb1, 0xb9, 0x97, 0x27, 0x19, 0x81,
0xb6, 0xe1, 0xb5, 0x20, 0xeb, 0x23, 0x92, 0x11, 0xb2, 0xf8, 0xb1, 0x33, 0x8d, 0x88, 0xcd, 0xed,
0x7e, 0x95, 0x81, 0x38, 0xf9, 0x4e, 0xac, 0x63, 0xe3, 0x4c, 0x6d, 0x61, 0x52, 0x09, 0x1e, 0x60,
0x59, 0xb3, 0x4e, 0x3f, 0x45, 0x6b, 0xbe, 0xa3, 0xb7, 0xd8, 0xe9, 0x59, 0x83, 0x74, 0x00, 0x5d,
0x4c, 0x7e, 0xfe, 0xc3, 0x9f, 0xfc, 0x55, 0x08, 0x50, 0x34, 0x77, 0xca, 0x2d, 0xec, 0xc3, 0x9c,
0x84, 0x65, 0x65, 0x70, 0x61, 0x53, 0x09, 0x6a, 0x2a, 0x8a, 0xe6, 0x73, 0x06, 0xd5, 0xaf, 0x40,
0xf4, 0x39, 0xff, 0x07, 0xa7, 0x40, 0x5b, 0x41, 0xb7, 0x9d, 0xb8, 0x42, 0x8d, 0xc5, 0x51, 0xcc,
0xf9, 0x27, 0x29, 0xf4, 0x47, 0x02, 0xac, 0xec, 0x63, 0x8b, 0x75, 0x08, 0xec, 0xff, 0x39, 0x0a,
0xb4, 0x9c, 0x9d, 0xf9, 0x9f, 0x98, 0x4c, 0xf1, 0x8d, 0xcf, 0xff, 0x33, 0xb5, 0x0c, 0x4b, 0x44,
0x06, 0x77, 0x2d, 0xb5, 0x25, 0x5b, 0x58, 0xa1, 0xf3, 0x23, 0x94, 0xcc, 0x75, 0x70, 0xae, 0x6f,
0x62, 0xc3, 0xfe, 0x1f, 0x29, 0xd4, 0x81, 0x98, 0x83, 0x22, 0x70, 0x76, 0x71, 0xf2, 0xec, 0x64,
0x5a, 0xf1, 0xb5, 0xa0, 0x59, 0xc9, 0xaa, 0xe9, 0x94, 0xb9, 0x0e, 0x46, 0x7f, 0x28, 0x40, 0xd2,
0x99, 0xcf, 0xfe, 0x87, 0x81, 0xa0, 0x69, 0xa7, 0xfc, 0xe7, 0x96, 0xab, 0x67, 0x2d, 0xde, 0x0d,
0x9a, 0xfd, 0x32, 0x5a, 0x71, 0x66, 0xcf, 0xf5, 0xf8, 0x84, 0xff, 0x20, 0xc0, 0x65, 0xf6, 0x98,
0x37, 0x0a, 0x64, 0x77, 0xc2, 0x84, 0x01, 0x1d, 0xd1, 0xf4, 0xad, 0x99, 0x40, 0x8a, 0xb9, 0x20,
0x80, 0x6b, 0x69, 0x3f, 0xc0, 0xc7, 0x42, 0x16, 0x7d, 0x29, 0x40, 0x92, 0x95, 0x89, 0x0c, 0x23,
0xfd, 0x38, 0xcb, 0x4d, 0x2b, 0x4a, 0x3d, 0x4d, 0xca, 0xc0, 0xec, 0xbe, 0x1f, 0x04, 0x67, 0x3d,
0x8d, 0x86, 0x70, 0xc8, 0x0f, 0x52, 0xbe, 0x13, 0x3c, 0xbf, 0x0f, 0x09, 0x27, 0x70, 0xac, 0x97,
0x19, 0x14, 0xb6, 0x29, 0x9f, 0xdc, 0x4e, 0x43, 0x50, 0xcc, 0x06, 0x81, 0x58, 0x41, 0xcb, 0x43,
0x10, 0xac, 0x2d, 0xf8, 0xb7, 0x02, 0xac, 0xb8, 0xdd, 0xc1, 0x20, 0xdc, 0x9f, 0x25, 0x60, 0xee,
0xd6, 0x57, 0xfa, 0xe6, 0x0c, 0xe0, 0xc4, 0x7b, 0x41, 0xc0, 0x56, 0xd3, 0x5e, 0x60, 0xc4, 0x35,
0x7f, 0x23, 0xc0, 0x8a, 0xaf, 0xdf, 0x37, 0x29, 0x99, 0x82, 0x9a, 0x83, 0x81, 0xe1, 0x7a, 0x3b,
0x08, 0xd0, 0x55, 0x71, 0xdd, 0x03, 0x28, 0xc7, 0xba, 0x4f, 0x03, 0x02, 0xec, 0x2b, 0x01, 0xb6,
0x24, 0x6c, 0xe2, 0xae, 0x52, 0x1e, 0xb8, 0x7a, 0xa7, 0x2d, 0x5a, 0xf0, 0x96, 0x27, 0xc5, 0x30,
0x08, 0x48, 0x3e, 0x08, 0xc8, 0xb6, 0x78, 0xd3, 0x07, 0xc4, 0xa0, 0x53, 0x9f, 0xb9, 0xe6, 0xf4,
0x26, 0x12, 0x6b, 0x2f, 0xbe, 0x64, 0x22, 0x39, 0x1d, 0xba, 0x19, 0x13, 0x89, 0xf5, 0xe9, 0xbc,
0x89, 0xc4, 0x20, 0xcc, 0x94, 0x48, 0xee, 0xa6, 0xd6, 0xb4, 0x44, 0xa2, 0xb2, 0x33, 0x26, 0x12,
0x05, 0x46, 0x5c, 0xa3, 0xc3, 0x8a, 0x84, 0x3b, 0xfa, 0x19, 0x9e, 0xc5, 0x3b, 0x41, 0x21, 0x0a,
0x76, 0x46, 0xd6, 0xe7, 0x8c, 0xbf, 0xf6, 0x64, 0xee, 0x54, 0x67, 0x8c, 0xef, 0xf0, 0xbd, 0x62,
0xde, 0x52, 0x2c, 0x41, 0x79, 0xeb, 0xea, 0x9c, 0xb2, 0x1c, 0x62, 0x7d, 0xa6, 0x6f, 0x24, 0x6f,
0x39, 0x90, 0xf1, 0x79, 0x3b, 0x72, 0x75, 0xd9, 0x0d, 0xab, 0x97, 0xbc, 0xba, 0x5c, 0x9d, 0xb9,
0x19, 0xaf, 0x2e, 0xde, 0xc1, 0xa1, 0xd7, 0x82, 0x83, 0xc2, 0x7e, 0xbc, 0xd8, 0x9e, 0x76, 0x2d,
0xd8, 0x4f, 0x28, 0xe9, 0x1b, 0x53, 0x25, 0x67, 0xc4, 0x63, 0xbf, 0x7d, 0x78, 0xaf, 0x52, 0xdb,
0x31, 0x33, 0x5d, 0xa5, 0xa3, 0x6d, 0xb4, 0x69, 0x57, 0xa9, 0xdd, 0xa5, 0x9a, 0xed, 0x2a, 0xe5,
0x0e, 0x23, 0x91, 0x3b, 0xe3, 0x35, 0x4e, 0xf9, 0x44, 0x0e, 0x8e, 0xd8, 0xeb, 0x33, 0xf5, 0x7c,
0x4c, 0xf1, 0x4e, 0xd0, 0xec, 0x49, 0x94, 0x18, 0xce, 0xde, 0x21, 0x53, 0xfd, 0x85, 0xeb, 0x0a,
0x77, 0x7a, 0x59, 0x13, 0x62, 0x35, 0xda, 0x23, 0x0b, 0xcc, 0xe5, 0x47, 0x41, 0x08, 0x32, 0xe9,
0x4d, 0x57, 0x2e, 0x73, 0x63, 0x66, 0x8e, 0xff, 0x37, 0x32, 0xf1, 0xc4, 0x3f, 0x0b, 0xb0, 0x45,
0x5d, 0x11, 0xf8, 0xe8, 0x12, 0xe4, 0x9e, 0xdd, 0x19, 0x60, 0x7b, 0x6c, 0x4d, 0x00, 0x8a, 0xae,
0xe5, 0x7a, 0x44, 0x46, 0xc5, 0xa6, 0x0b, 0x68, 0xcb, 0x31, 0x80, 0x3e, 0x83, 0x58, 0x5e, 0x51,
0xca, 0x27, 0x72, 0xb5, 0x51, 0x0b, 0xc4, 0xb4, 0x3d, 0xb1, 0xb9, 0xe6, 0x6a, 0x88, 0x4d, 0x48,
0x19, 0x71, 0x65, 0x24, 0x68, 0x39, 0xdd, 0xea, 0x11, 0x47, 0x7d, 0x21, 0xb8, 0x9b, 0x88, 0x8d,
0x1a, 0x7a, 0x7d, 0xea, 0x6d, 0x4e, 0x67, 0x0c, 0x0c, 0xda, 0x6f, 0x05, 0x21, 0xb8, 0x96, 0xde,
0xf0, 0x21, 0x70, 0x9f, 0x85, 0x1a, 0x2c, 0xf2, 0x3b, 0x61, 0xb2, 0x33, 0x82, 0x26, 0x0e, 0xde,
0xce, 0x59, 0xff, 0xd2, 0xd1, 0xbf, 0x09, 0xb0, 0xc2, 0x3f, 0x32, 0x07, 0xce, 0x47, 0xef, 0xc4,
0xdb, 0x71, 0x6c, 0x57, 0x2e, 0xfd, 0xe0, 0x02, 0x1a, 0x3c, 0x46, 0x6f, 0x05, 0x01, 0xdd, 0x14,
0xd7, 0x28, 0xd0, 0x36, 0x51, 0xa2, 0x68, 0x9b, 0x26, 0x55, 0x25, 0xee, 0xf9, 0x1f, 0x01, 0x2e,
0xdb, 0x80, 0x87, 0x1f, 0xe0, 0x26, 0x7a, 0xf3, 0x22, 0x0f, 0xfb, 0x36, 0xea, 0xb7, 0x2e, 0xa6,
0xc4, 0x81, 0x07, 0xa7, 0xb9, 0xb8, 0x99, 0x6b, 0x6b, 0xfa, 0xb1, 0xac, 0x91, 0xc2, 0x9e, 0x28,
0xeb, 0x46, 0xdb, 0x74, 0xa3, 0xff, 0x73, 0x01, 0xd6, 0xe9, 0x7e, 0xfc, 0x90, 0x4d, 0xe9, 0x7e,
0x21, 0x7f, 0x89, 0xaa, 0x68, 0xe4, 0x89, 0x5d, 0xdc, 0x0d, 0xc2, 0xb5, 0x81, 0xd6, 0x73, 0xae,
0x97, 0xf6, 0x1c, 0x37, 0x45, 0xbe, 0xcf, 0xfe, 0xd8, 0x06, 0xc4, 0x57, 0xfb, 0x2b, 0x05, 0x34,
0xb1, 0x4c, 0x73, 0x03, 0xea, 0xe0, 0x27, 0xff, 0x21, 0x7c, 0x95, 0xff, 0x13, 0x01, 0xbd, 0x03,
0xd1, 0x7c, 0xdf, 0x3a, 0xcd, 0xe4, 0x6b, 0x25, 0x31, 0x8b, 0xb6, 0x4f, 0x2d, 0xab, 0x67, 0x3e,
0xce, 0xe5, 0xda, 0xaa, 0x75, 0xda, 0x3f, 0xde, 0x69, 0xe9, 0x9d, 0x1c, 0x99, 0xdb, 0x59, 0x41,
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.
var _ context.Context
var _ grpc.ClientConn
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// 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.
//
@ -3323,6 +3366,7 @@ type AuthServiceClient interface {
GetMyUser(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserView, error)
GetMyUserProfile(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*UserProfileView, 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)
ChangeMyUserEmail(ctx context.Context, in *UpdateUserEmailRequest, opts ...grpc.CallOption) (*UserEmail, error)
VerifyMyUserEmail(ctx context.Context, in *VerifyMyUserEmailRequest, opts ...grpc.CallOption) (*empty.Empty, error)
@ -3351,10 +3395,10 @@ type AuthServiceClient interface {
}
type authServiceClient struct {
cc *grpc.ClientConn
cc grpc.ClientConnInterface
}
func NewAuthServiceClient(cc *grpc.ClientConn) AuthServiceClient {
func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
return &authServiceClient{cc}
}
@ -3421,6 +3465,15 @@ func (c *authServiceClient) UpdateMyUserProfile(ctx context.Context, in *UpdateU
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) {
out := new(UserEmailView)
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)
GetMyUserProfile(context.Context, *empty.Empty) (*UserProfileView, error)
UpdateMyUserProfile(context.Context, *UpdateUserProfileRequest) (*UserProfile, error)
ChangeMyUserName(context.Context, *ChangeUserNameRequest) (*empty.Empty, error)
GetMyUserEmail(context.Context, *empty.Empty) (*UserEmailView, error)
ChangeMyUserEmail(context.Context, *UpdateUserEmailRequest) (*UserEmail, 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) {
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) {
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)
}
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) {
in := new(empty.Empty)
if err := dec(in); err != nil {
@ -4308,6 +4383,10 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{
MethodName: "UpdateMyUserProfile",
Handler: _AuthService_UpdateMyUserProfile_Handler,
},
{
MethodName: "ChangeMyUserName",
Handler: _AuthService_ChangeMyUserName_Handler,
},
{
MethodName: "GetMyUserEmail",
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": {
"get": {
"operationId": "Validate",
@ -665,6 +691,14 @@
}
}
},
"v1ChangeUserNameRequest": {
"type": "object",
"properties": {
"user_name": {
"type": "string"
}
}
},
"v1Changes": {
"type": "object",
"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...)
}
// 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
func (m *MockAuthServiceClient) ChangeMyUserPhone(arg0 context.Context, arg1 *auth.UpdateUserPhoneRequest, arg2 ...grpc.CallOption) (*auth.UserPhone, error) {
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) {
option (google.api.http) = {
get: "/users/me/email"
@ -437,6 +448,10 @@ message UpdateUserProfileRequest {
Gender gender = 5;
}
message ChangeUserNameRequest {
string user_name = 1 [(validate.rules).string = {max_len: 200}];
}
message UserEmail {
string id = 1;
string email = 2;

View File

@ -24,8 +24,8 @@ var ManagementService_AuthMethods = authz.MethodMapping{
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/GetUserByEmailGlobal": authz.Option{
Permission: "user.read",
"/caos.zitadel.management.api.v1.ManagementService/GetUserByLoginNameGlobal": authz.Option{
Permission: "user.global.read",
CheckParam: "",
},
@ -104,6 +104,11 @@ var ManagementService_AuthMethods = authz.MethodMapping{
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/ChangeUserUserName": authz.Option{
Permission: "user.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/ChangeUserEmail": authz.Option{
Permission: "user.write",
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...)
}
// 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
func (m *MockManagementServiceClient) CreateLoginPolicy(arg0 context.Context, arg1 *management.LoginPolicyAdd, arg2 ...grpc.CallOption) (*management.LoginPolicy, error) {
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...)
}
// 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
func (m *MockManagementServiceClient) GetUserByID(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserView, error) {
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...)
}
// 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
func (m *MockManagementServiceClient) GetUserEmail(arg0 context.Context, arg1 *management.UserID, arg2 ...grpc.CallOption) (*management.UserEmailView, error) {
m.ctrl.T.Helper()

View File

@ -81,14 +81,14 @@ service ManagementService {
};
}
// GetUserByEmailGlobal returns User, global search is overall organisations
rpc GetUserByEmailGlobal(Email) returns (UserView) {
// GetUserByLoginNameGlobal returns User, global search is overall organisations
rpc GetUserByLoginNameGlobal(LoginName) returns (UserView) {
option (google.api.http) = {
get: "/global/users/_byemail"
get: "/global/users/_byloginname"
};
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) {
option (google.api.http) = {
put: "/users/{id}/email"
@ -1459,8 +1469,8 @@ message UserID {
string id = 1;
}
message Email {
string email = 1;
message LoginName {
string login_name = 1;
}
message UniqueUserRequest {
@ -1648,6 +1658,11 @@ message UpdateUserProfileRequest {
Gender gender = 6;
}
message UpdateUserUserNameRequest {
string id = 1;
string user_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
}
message UserEmail {
string id = 1;
string email = 2;