cherry pick changes from main (#3371)

* feat: remove exif data from uploaded images (#3221)

* feat: remove exif tags from images

* feat: remove exif data

* feat: remove exif

* fix: add preferredLoginName to user grant response (#3271)

* chore: log webauthn parse error (#3272)

* log error

* log error

* feat: Help link in privacy policy

* fix: convert correct detail data on organization (#3279)

* fix: handle empty editor users

* fix: add some missing translations (#3291)

* fix: org policy translations

* fix: metadata event types translation

* fix: translations

* fix: filter resource owner correctly on project grant members (#3281)

* fix: filter resource owner correctly on project grant members

* fix: filter resource owner correctly on project grant members

* fix: add orgIDs to zitadel permissions request

Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>

* fix: get IAM memberships correctly in MyZitadelPermissions (#3309)

* fix: correct login names on auth and notification users (#3349)

* fix: correct login names on auth and notification users

* fix: migration

* fix: handle resource owner in action flows (#3361)

* fix merge

* fix: exchange exif library (#3366)

* fix: exchange exif library

* ignore tiffs

* requested fixes

* feat: Help link in privacy policy

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Livio Amstutz 2022-03-24 14:00:24 +01:00 committed by GitHub
parent 56b916a2b0
commit 504fe5b761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 1055 additions and 602 deletions

View File

@ -1,16 +1,18 @@
<div *ngIf="currentMap"> <div *ngIf="currentMap">
<form [formGroup]="form" > <form [formGroup]="form">
<ng-container *ngFor="let key of (current$ | async) | keyvalue"> <ng-container *ngFor="let key of (current$ | async) | keyvalue">
<div class="block"> <div class="block">
<div class="flex" *ngIf="(default$ | async) as defaultmap"> <div class="flex" *ngIf="(default$ | async) as defaultmap">
<cnsl-form-field class="formfield" > <cnsl-form-field class="formfield">
<cnsl-label>{{key.key}}</cnsl-label> <cnsl-label>{{key.key}}</cnsl-label>
<textarea class="text" cnslInput [formControlName]="key.key" [placeholder]="defaultmap[key.key]" [name]="key.key" [ngClass]="{'defaulttext': form.get(key.key)?.value === ''}"></textarea> <textarea class="text" cnslInput [formControlName]="key.key" [placeholder]="defaultmap[key.key]"
[name]="key.key" [ngClass]="{'defaulttext': form.get(key.key)?.value === ''}"></textarea>
<div class="chips" *ngIf="warnText[key.key] === undefined"> <div class="chips" *ngIf="warnText[key.key] === undefined">
<ng-container *ngFor="let chip of chips" > <ng-container *ngFor="let chip of chips">
<div class="chip" cnslCopyToClipboard [valueToCopy]="chip.value" (copiedValue)="copied = $event" (click)="addChip(key.key, chip.value)"> <div class="chip" cnslCopyToClipboard [valueToCopy]="chip.value" (copiedValue)="copied = $event"
(click)="addChip(key.key, chip.value)">
<span class="key">{{chip.key | translate}}</span> <span class="key">{{chip.key | translate}}</span>
<span class="value">{{chip.value}}</span> <span class="value">{{chip.value}}</span>
<i *ngIf="copied !== chip.value" class="las la-clipboard"></i> <i *ngIf="copied !== chip.value" class="las la-clipboard"></i>
@ -20,12 +22,21 @@
</div> </div>
</cnsl-form-field> </cnsl-form-field>
<div class="actions"> <div class="actions">
<button matTooltip="{{'ACTIONS.RESETDEFAULT'| translate }}" mat-icon-button [disabled]="form.get(key.key)?.value === defaultmap[key.key] || disabled" (click)="form.get(key.key)?.setValue(defaultmap[key.key])" (mouseenter) = "form.get(key.key)?.value !== defaultmap[key.key] && setWarnText(key.key, defaultmap[key.key])" (mouseleave) ="setWarnText(key.key, undefined)"><i class="las la-history"></i></button> <button matTooltip="{{'ACTIONS.RESETDEFAULT'| translate }}" mat-icon-button
<button matTooltip="{{'ACTIONS.RESETCURRENT'| translate }}" mat-icon-button [disabled]="form.get(key.key)?.value === currentMap[key.key] || disabled" (click)="form.get(key.key)?.setValue(currentMap[key.key])" (mouseenter) = "form.get(key.key)?.value !== currentMap[key.key] && setWarnText(key.key, currentMap[key.key])" (mouseleave) ="setWarnText(key.key, undefined)"><i class="las la-undo"></i></button> [disabled]="form.get(key.key)?.value === defaultmap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(defaultmap[key.key])"
(mouseenter)="form.get(key.key)?.value !== defaultmap[key.key] && setWarnText(key.key, defaultmap[key.key])"
(mouseleave)="setWarnText(key.key, undefined)"><i class="las la-history"></i></button>
<button matTooltip="{{'ACTIONS.RESETCURRENT'| translate }}" mat-icon-button
[disabled]="form.get(key.key)?.value === currentMap[key.key] || disabled"
(click)="form.get(key.key)?.setValue(currentMap[key.key])"
(mouseenter)="form.get(key.key)?.value !== currentMap[key.key] && setWarnText(key.key, currentMap[key.key])"
(mouseleave)="setWarnText(key.key, undefined)"><i class="las la-undo"></i></button>
</div> </div>
</div> </div>
</div> </div>
<cnsl-info-section *ngIf="warnText[key.key] !== undefined" class="info" [type]="InfoSectionType.WARN">{{'ACTIONS.RESETTO'| translate }} <cite>'{{warnText[key.key]}}'</cite></cnsl-info-section> <cnsl-info-section *ngIf="warnText[key.key] !== undefined" class="info" [type]="InfoSectionType.WARN">
{{'ACTIONS.RESETTO'| translate }} <cite>'{{warnText[key.key]}}'</cite></cnsl-info-section>
</ng-container> </ng-container>
</form> </form>
</div> </div>

View File

@ -71,7 +71,6 @@ export function mapRequestValues(map: Partial<Map>, req: Req): Req {
const r3 = new FooterText(); const r3 = new FooterText();
r3.setHelp(map.footerText?.help ?? ''); r3.setHelp(map.footerText?.help ?? '');
r3.setHelpLink(map.footerText?.helpLink ?? '');
r3.setPrivacyPolicy(map.footerText?.privacyPolicy ?? ''); r3.setPrivacyPolicy(map.footerText?.privacyPolicy ?? '');
r3.setTos(map.footerText?.tos ?? ''); r3.setTos(map.footerText?.tos ?? '');
req.setFooterText(r3); req.setFooterText(r3);
@ -102,7 +101,6 @@ export function mapRequestValues(map: Partial<Map>, req: Req): Req {
r6.setU2fOption(map.initMfaPromptText?.otpOption ?? ''); r6.setU2fOption(map.initMfaPromptText?.otpOption ?? '');
req.setInitMfaPromptText(r6); req.setInitMfaPromptText(r6);
const r7 = new InitMFAU2FScreenText(); const r7 = new InitMFAU2FScreenText();
r7.setDescription(map.initMfaU2fText?.description ?? ''); r7.setDescription(map.initMfaU2fText?.description ?? '');
r7.setErrorRetry(map.initMfaU2fText?.errorRetry ?? ''); r7.setErrorRetry(map.initMfaU2fText?.errorRetry ?? '');
@ -112,7 +110,6 @@ export function mapRequestValues(map: Partial<Map>, req: Req): Req {
r7.setTokenNameLabel(map.initMfaU2fText?.tokenNameLabel ?? ''); r7.setTokenNameLabel(map.initMfaU2fText?.tokenNameLabel ?? '');
req.setInitMfaU2fText(r7); req.setInitMfaU2fText(r7);
const r8 = new InitPasswordDoneScreenText(); const r8 = new InitPasswordDoneScreenText();
r8.setCancelButtonText(map.initPasswordDoneText?.cancelButtonText ?? ''); r8.setCancelButtonText(map.initPasswordDoneText?.cancelButtonText ?? '');
r8.setDescription(map.initPasswordDoneText?.description ?? ''); r8.setDescription(map.initPasswordDoneText?.description ?? '');
@ -348,7 +345,6 @@ export function mapRequestValues(map: Partial<Map>, req: Req): Req {
r32.setTokenNameLabel(map.passwordlessRegistrationText?.tokenNameLabel ?? ''); r32.setTokenNameLabel(map.passwordlessRegistrationText?.tokenNameLabel ?? '');
req.setPasswordlessRegistrationText(r32); req.setPasswordlessRegistrationText(r32);
const r33 = new PasswordlessScreenText(); const r33 = new PasswordlessScreenText();
r33.setDescription(map.passwordlessText?.description ?? ''); r33.setDescription(map.passwordlessText?.description ?? '');
r33.setErrorRetry(map.passwordlessText?.errorRetry ?? ''); r33.setErrorRetry(map.passwordlessText?.errorRetry ?? '');

View File

@ -1,35 +1,59 @@
<cnsl-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']" <cnsl-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.PRIVACY_POLICY.TITLE' | translate" [title]="'POLICY.PRIVACY_POLICY.TITLE' | translate" [description]="'POLICY.PRIVACY_POLICY.DESCRIPTION' | translate">
[description]="'POLICY.PRIVACY_POLICY.DESCRIPTION' | translate">
<cnsl-info-section *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</cnsl-info-section> <cnsl-info-section *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</cnsl-info-section>
<cnsl-info-section *ngIf="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false" [featureLink]="['/org/features']" class="info" [type]="InfoSectionType.WARN"> <cnsl-info-section
*ngIf="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false"
[featureLink]="['/org/features']" class="info" [type]="InfoSectionType.WARN">
<span [innerHTML]="'FEATURES.NOTAVAILABLE' | translate: ({value: 'privacy_policy'})"></span> <span [innerHTML]="'FEATURES.NOTAVAILABLE' | translate: ({value: 'privacy_policy'})"></span>
</cnsl-info-section> </cnsl-info-section>
<div class="divider"></div> <div class="divider"></div>
<div class="content" > <div class="content">
<form *ngIf="form" [formGroup]="form"> <form *ngIf="form" [formGroup]="form">
<cnsl-form-field class="formfield"> <cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.TOSLINK' | translate }}</cnsl-label> <cnsl-label>{{ 'POLICY.PRIVACY_POLICY.TOSLINK' | translate }}</cnsl-label>
<input cnslInput name="tosLink" formControlName="tosLink" /> <input cnslInput name="tosLink" formControlName="tosLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{key: 'tosLink'}"></template>
</cnsl-form-field> </cnsl-form-field>
<cnsl-form-field class="formfield"> <cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.POLICYLINK' | translate }}</cnsl-label> <cnsl-label>{{ 'POLICY.PRIVACY_POLICY.POLICYLINK' | translate }}</cnsl-label>
<input cnslInput name="privacyLink" formControlName="privacyLink" /> <input cnslInput name="privacyLink" formControlName="privacyLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{key: 'privacyLink'}"></template>
</cnsl-form-field>
<cnsl-form-field class="privacy-policy-formfield">
<cnsl-label>{{ 'POLICY.PRIVACY_POLICY.HELPLINK' | translate }}</cnsl-label>
<input cnslInput name="helpLink" formControlName="helpLink" />
<template [ngTemplateOutlet]="templateRef" [ngTemplateOutletContext]="{key: 'helpLink'}"></template>
</cnsl-form-field> </cnsl-form-field>
</form> </form>
</div> </div>
<div class="actions"> <div class="actions">
<button *ngIf="!privacyPolicy?.isDefault" class="reset-button" [disabled]="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false" (click)="resetDefault()" color="warn" type="submit" <button *ngIf="privacyPolicy && privacyPolicy.isDefault === false" class="reset-button"
mat-stroked-button><i class="las la-history"></i> {{ 'ACTIONS.RESETDEFAULT' | translate }}</button> [disabled]="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false"
<button class="save-button" [disabled]="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false" (click)="saveCurrentMessage()" color="primary" type="submit" (click)="resetDefault()" color="warn" type="submit" mat-stroked-button><i class="las la-history"></i> {{
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button> 'ACTIONS.RESETDEFAULT' | translate }}</button>
<button class="save-button"
[disabled]="serviceType === PolicyComponentServiceType.MGMT && (['privacy_policy'] | hasFeature | async) === false"
(click)="saveCurrentMessage()" color="primary" type="submit" mat-raised-button>{{ 'ACTIONS.SAVE' | translate
}}</button>
</div> </div>
<cnsl-policy-grid [currentPolicy]="currentPolicy" [type]="serviceType" tagForFilter="text"></cnsl-policy-grid> <cnsl-policy-grid [currentPolicy]="currentPolicy" [type]="serviceType" tagForFilter="text"></cnsl-policy-grid>
</cnsl-detail-layout> </cnsl-detail-layout>
<ng-template #templateRef let-key="key">
<div class="chips">
<div class="chip" cnslCopyToClipboard [valueToCopy]="LANGPLACEHOLDER" (copiedValue)="copied = $event"
(click)="addChip(key, LANGPLACEHOLDER)">
<span class="key">{{LANGPLACEHOLDER}}</span>
<i *ngIf="copied !== LANGPLACEHOLDER" class="las la-clipboard"></i>
<i *ngIf="copied === LANGPLACEHOLDER" class="las la-clipboard-check"></i>
</div>
</div>
</ng-template>

View File

@ -1,26 +1,26 @@
.spinner-wr { .spinner-wr {
margin: .5rem 0; margin: 0.5rem 0;
} }
.top-actions { .top-actions {
display: flex; display: flex;
margin: 0 -.5rem; margin: 0 -0.5rem;
flex-wrap: wrap; flex-wrap: wrap;
.keys { .keys {
flex: 1; flex: 1;
margin: 0 .5rem; margin: 0 0.5rem;
min-width: 150px; min-width: 150px;
} }
.language { .language {
margin: 0 .5rem; margin: 0 0.5rem;
min-width: 150px; min-width: 150px;
.lighter { .lighter {
font-size: 12px; font-size: 12px;
color: var(--grey); color: var(--grey);
padding: 0 .5rem; padding: 0 0.5rem;
} }
} }
} }
@ -34,40 +34,66 @@
padding-top: 1rem; padding-top: 1rem;
} }
.chips { .privacy-policy-formfield {
.chips {
display: flex; display: flex;
margin: 0 -.25rem; flex-wrap: wrap;
opacity: 0;
margin: 0 -0.25rem;
transition: all 0.2s ease;
.chip { .chip {
border-radius: 50vw; border-radius: 50vw;
padding: 2px .5rem; padding: 4px 0.5rem;
font-size: 12px; font-size: 12px;
background: #cbf4c9; background: #5282c1;
color: #0e6245; color: white;
margin: .25rem; margin: 0.25rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 10; z-index: 10;
* {
transition: all 0.2s ease;
}
i {
opacity: 0.5;
font-size: 1.1rem;
margin-left: 0.5rem;
}
.key {
display: inline-block;
}
}
}
&.cnsl-focused {
.chips {
opacity: 1;
cursor: copy;
}
} }
} }
.divider { .divider {
width: 100%; width: 100%;
height: 1px; height: 1px;
background-color: rgba(#81868a, .5); background-color: rgba(#81868a, 0.5);
margin: 1.5rem 0 0 0; margin: 1.5rem 0 0 0;
} }
.actions { .actions {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin: 0 -.25rem; margin: 0 -0.25rem;
.save-button, .save-button,
.reset-button { .reset-button {
display: block; display: block;
margin: 0 .25rem 3rem .25rem; margin: 0 0.25rem 3rem 0.25rem;
} }
.reset-button { .reset-button {

View File

@ -37,11 +37,14 @@ export class PrivacyPolicyComponent implements OnDestroy {
public nextLinks: CnslLinks[] = []; public nextLinks: CnslLinks[] = [];
private sub: Subscription = new Subscription(); private sub: Subscription = new Subscription();
public privacyPolicy!: PrivacyPolicy.AsObject; public privacyPolicy: PrivacyPolicy.AsObject | undefined = undefined;
public form!: FormGroup; public form!: FormGroup;
public currentPolicy: GridPolicy = PRIVACY_POLICY; public currentPolicy: GridPolicy = PRIVACY_POLICY;
public InfoSectionType: any = InfoSectionType; public InfoSectionType: any = InfoSectionType;
public LANGPLACEHOLDER: string = '{{.Lang}}';
public copied: string = '';
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
private injector: Injector, private injector: Injector,
@ -49,13 +52,15 @@ export class PrivacyPolicyComponent implements OnDestroy {
private toast: ToastService, private toast: ToastService,
private fb: FormBuilder, private fb: FormBuilder,
) { ) {
this.form = this.fb.group({ this.form = this.fb.group({
tosLink: ['', []], tosLink: ['', []],
privacyLink: ['', []], privacyLink: ['', []],
helpLink: ['', []],
}); });
this.route.data.pipe(switchMap(data => { this.route.data
.pipe(
switchMap((data) => {
this.serviceType = data.serviceType; this.serviceType = data.serviceType;
switch (this.serviceType) { switch (this.serviceType) {
case PolicyComponentServiceType.MGMT: case PolicyComponentServiceType.MGMT:
@ -69,50 +74,86 @@ export class PrivacyPolicyComponent implements OnDestroy {
} }
return this.route.params; return this.route.params;
})).subscribe(); }),
)
.subscribe();
}
public addChip(formControlName: string, value: string): void {
const c = this.form.get(formControlName)?.value;
this.form.get(formControlName)?.setValue(`${c}${value}`);
} }
public async loadData(): Promise<any> { public async loadData(): Promise<any> {
const getData = (): const getData = (): Promise<AdminGetPrivacyPolicyResponse.AsObject | GetPrivacyPolicyResponse.AsObject> => {
Promise<AdminGetPrivacyPolicyResponse.AsObject | GetPrivacyPolicyResponse.AsObject> => { return this.service.getPrivacyPolicy();
return (this.service as AdminService).getPrivacyPolicy();
}; };
getData().then(resp => { getData()
.then((resp) => {
if (resp.policy) { if (resp.policy) {
this.privacyPolicy = resp.policy; this.privacyPolicy = resp.policy;
this.form.patchValue(this.privacyPolicy); this.form.patchValue(this.privacyPolicy);
} else {
this.privacyPolicy = undefined;
this.form.patchValue({
tosLink: '',
privacyLink: '',
helpLink: '',
});
} }
})
.catch((error) => {
this.privacyPolicy = undefined;
this.form.patchValue({
tosLink: '',
privacyLink: '',
helpLink: '',
});
}); });
} }
public saveCurrentMessage(): void { public saveCurrentMessage(): void {
console.log(this.form.get('privacyLink')?.value, this.form.get('tosLink')?.value);
if (this.serviceType === PolicyComponentServiceType.MGMT) { if (this.serviceType === PolicyComponentServiceType.MGMT) {
if ((this.privacyPolicy as PrivacyPolicy.AsObject).isDefault) { if (!this.privacyPolicy || (this.privacyPolicy as PrivacyPolicy.AsObject).isDefault) {
const req = new AddCustomPrivacyPolicyRequest(); const req = new AddCustomPrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value); req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value); req.setTosLink(this.form.get('tosLink')?.value);
(this.service as ManagementService).addCustomPrivacyPolicy(req).then(() => { req.setHelpLink(this.form.get('helpLink')?.value);
(this.service as ManagementService)
.addCustomPrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true); this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
}).catch(error => this.toast.showError(error)); this.loadData();
})
.catch((error) => this.toast.showError(error));
} else { } else {
const req = new UpdateCustomPrivacyPolicyRequest(); const req = new UpdateCustomPrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value); req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value); req.setTosLink(this.form.get('tosLink')?.value);
(this.service as ManagementService).updateCustomPrivacyPolicy(req).then(() => { req.setHelpLink(this.form.get('helpLink')?.value);
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
}).catch(error => this.toast.showError(error));
}
(this.service as ManagementService)
.updateCustomPrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
this.loadData();
})
.catch((error) => this.toast.showError(error));
}
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) { } else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
const req = new UpdatePrivacyPolicyRequest(); const req = new UpdatePrivacyPolicyRequest();
req.setPrivacyLink(this.form.get('privacyLink')?.value); req.setPrivacyLink(this.form.get('privacyLink')?.value);
req.setTosLink(this.form.get('tosLink')?.value); req.setTosLink(this.form.get('tosLink')?.value);
req.setHelpLink(this.form.get('helpLink')?.value);
(this.service as AdminService).updatePrivacyPolicy(req).then(() => { (this.service as AdminService)
.updatePrivacyPolicy(req)
.then(() => {
this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true); this.toast.showInfo('POLICY.PRIVACY_POLICY.SAVED', true);
}).catch(error => this.toast.showError(error)); this.loadData();
})
.catch((error) => this.toast.showError(error));
} }
} }
@ -128,14 +169,17 @@ export class PrivacyPolicyComponent implements OnDestroy {
width: '400px', width: '400px',
}); });
dialogRef.afterClosed().subscribe(resp => { dialogRef.afterClosed().subscribe((resp) => {
if (resp) { if (resp) {
if (this.serviceType === PolicyComponentServiceType.MGMT) { if (this.serviceType === PolicyComponentServiceType.MGMT) {
(this.service as ManagementService).resetPrivacyPolicyToDefault().then(() => { (this.service as ManagementService)
.resetPrivacyPolicyToDefault()
.then(() => {
setTimeout(() => { setTimeout(() => {
this.loadData(); this.loadData();
}, 1000); }, 1000);
}).catch(error => { })
.catch((error) => {
this.toast.showError(error); this.toast.showError(error);
}); });
} }

View File

@ -9,6 +9,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
import { HasRoleModule } from '../../../directives/has-role/has-role.module'; import { HasRoleModule } from '../../../directives/has-role/has-role.module';
import { DetailLayoutModule } from '../../../modules/detail-layout/detail-layout.module'; import { DetailLayoutModule } from '../../../modules/detail-layout/detail-layout.module';
@ -32,6 +33,7 @@ import { PrivacyPolicyComponent } from './privacy-policy.component';
FormsModule, FormsModule,
InputModule, InputModule,
FormFieldModule, FormFieldModule,
CopyToClipboardModule,
MatButtonModule, MatButtonModule,
HasFeaturePipeModule, HasFeaturePipeModule,
MatIconModule, MatIconModule,
@ -49,4 +51,4 @@ import { PrivacyPolicyComponent } from './privacy-policy.component';
InfoSectionModule, InfoSectionModule,
], ],
}) })
export class PrivacyPolicyModule { } export class PrivacyPolicyModule {}

View File

@ -873,6 +873,7 @@
"DESCRIPTION": "Legen Sie Ihre Datenschutzrichtlinien und Nutzungsbedingungen fest", "DESCRIPTION": "Legen Sie Ihre Datenschutzrichtlinien und Nutzungsbedingungen fest",
"TOSLINK": "Link zu den Allgemeinen Geschäftsbedingungen", "TOSLINK": "Link zu den Allgemeinen Geschäftsbedingungen",
"POLICYLINK": "Link zur den Datenschutzrichtlinien", "POLICYLINK": "Link zur den Datenschutzrichtlinien",
"HELPLINK": "Link zur Hilfestellung",
"SAVED": "Saved successfully!", "SAVED": "Saved successfully!",
"RESET_TITLE": "Standardwerte wiederherstellen", "RESET_TITLE": "Standardwerte wiederherstellen",
"RESET_DESCRIPTION": "Sie sind im Begriff die Standardlinks für die AGBs und Datenschutzrichtlinie wiederherzustellen. Wollen Sie fortfahren?" "RESET_DESCRIPTION": "Sie sind im Begriff die Standardlinks für die AGBs und Datenschutzrichtlinie wiederherzustellen. Wollen Sie fortfahren?"

View File

@ -873,6 +873,7 @@
"DESCRIPTION": "Set your Privacy Policy and Terms of Service Links", "DESCRIPTION": "Set your Privacy Policy and Terms of Service Links",
"TOSLINK": "Link to Terms of Service", "TOSLINK": "Link to Terms of Service",
"POLICYLINK": "Link to Privacy Policy", "POLICYLINK": "Link to Privacy Policy",
"HELPLINK": "Link to Help",
"SAVED": "Saved successfully!", "SAVED": "Saved successfully!",
"RESET_TITLE": "Restore Default Values", "RESET_TITLE": "Restore Default Values",
"RESET_DESCRIPTION": "You are about to restore the default Links for TOS and Privacy Policy. Do you really want to continue?" "RESET_DESCRIPTION": "You are about to restore the default Links for TOS and Privacy Policy. Do you really want to continue?"

View File

@ -873,6 +873,7 @@
"DESCRIPTION": "Imposta i tuoi link all'informativa sulla privacy e ai termini di servizio", "DESCRIPTION": "Imposta i tuoi link all'informativa sulla privacy e ai termini di servizio",
"TOSLINK": "Link ai termini di servizio", "TOSLINK": "Link ai termini di servizio",
"POLICYLINK": "Link all'informativa sulla privacy", "POLICYLINK": "Link all'informativa sulla privacy",
"HELPLINK": "link per l'aiuto",
"SAVED": "Salvato con successo!", "SAVED": "Salvato con successo!",
"RESET_TITLE": "Ripristina i valori predefiniti", "RESET_TITLE": "Ripristina i valori predefiniti",
"RESET_DESCRIPTION": "Stai per ripristinare i link predefiniti per i TOS e l'informativa sulla privacy. Vuoi davvero continuare?" "RESET_DESCRIPTION": "Stai per ripristinare i link predefiniti per i TOS e l'informativa sulla privacy. Vuoi davvero continuare?"

View File

@ -888,6 +888,7 @@ Returns the privacy policy defined by the administrators of ZITADEL
Updates the default privacy policy of ZITADEL Updates the default privacy policy of ZITADEL
it impacts all organisations without a customised policy it impacts all organisations without a customised policy
Variable {{.Lang}} can be set to have different links based on the language
@ -3816,6 +3817,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| tos_link | string | - | | | tos_link | string | - | |
| privacy_link | string | - | | | privacy_link | string | - | |
| help_link | string | - | |

View File

@ -2095,6 +2095,7 @@ With this policy the privacy relevant things can be configured (e.g tos link)
Add a custom privacy policy for the organisation Add a custom privacy policy for the organisation
With this policy privacy relevant things can be configured (e.g. tos link) With this policy privacy relevant things can be configured (e.g. tos link)
Variable {{.Lang}} can be set to have different links based on the language
@ -2108,6 +2109,7 @@ With this policy privacy relevant things can be configured (e.g. tos link)
Update the privacy complexity policy for the organisation Update the privacy complexity policy for the organisation
With this policy privacy relevant things can be configured (e.g. tos link) With this policy privacy relevant things can be configured (e.g. tos link)
Variable {{.Lang}} can be set to have different links based on the language
@ -3113,6 +3115,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| tos_link | string | - | | | tos_link | string | - | |
| privacy_link | string | - | | | privacy_link | string | - | |
| help_link | string | - | |
@ -7833,6 +7836,7 @@ This is an empty request
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| tos_link | string | - | | | tos_link | string | - | |
| privacy_link | string | - | | | privacy_link | string | - | |
| help_link | string | - | |

View File

@ -126,6 +126,7 @@ title: zitadel/policy.proto
| tos_link | string | - | | | tos_link | string | - | |
| privacy_link | string | - | | | privacy_link | string | - | |
| is_default | bool | - | | | is_default | bool | - | |
| help_link | string | - | |

View File

@ -93,7 +93,6 @@ title: zitadel/text.proto
| tos | string | - | string.max_len: 200<br /> | | tos | string | - | string.max_len: 200<br /> |
| privacy_policy | string | - | string.max_len: 200<br /> | | privacy_policy | string | - | string.max_len: 200<br /> |
| help | string | - | string.max_len: 200<br /> | | help | string | - | string.max_len: 200<br /> |
| help_link | string | - | string.max_len: 500<br /> |

View File

@ -374,6 +374,7 @@ UserTypeQuery is always equals
| project_name | string | - | | | project_name | string | - | |
| project_grant_id | string | - | | | project_grant_id | string | - | |
| avatar_url | string | - | | | avatar_url | string | - | |
| preferred_login_name | string | - | |

15
go.mod
View File

@ -44,10 +44,12 @@ require (
github.com/pquerna/otp v1.3.0 github.com/pquerna/otp v1.3.0
github.com/rakyll/statik v0.1.7 github.com/rakyll/statik v0.1.7
github.com/rs/cors v1.8.0 github.com/rs/cors v1.8.0
github.com/sirupsen/logrus v1.8.1
github.com/sony/sonyflake v1.0.0 github.com/sony/sonyflake v1.0.0
github.com/spf13/cobra v1.3.0 github.com/spf13/cobra v1.3.0
github.com/spf13/viper v1.10.1 github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
github.com/ttacon/libphonenumber v1.2.1 github.com/ttacon/libphonenumber v1.2.1
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.27.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.27.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0
@ -88,17 +90,28 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc // indirect
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 // indirect
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb // indirect
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 // indirect
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d // indirect
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c // indirect
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 // indirect
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fxamacker/cbor/v2 v2.2.0 // indirect github.com/fxamacker/cbor/v2 v2.2.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.2 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.0.21 // indirect github.com/google/certificate-transparency-go v1.0.21 // indirect
@ -107,6 +120,7 @@ require (
github.com/googleapis/gax-go/v2 v2.1.1 // indirect github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/h2non/filetype v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.12 // indirect
@ -139,7 +153,6 @@ require (
github.com/prometheus/procfs v0.6.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect
github.com/rs/xid v1.2.1 // indirect github.com/rs/xid v1.2.1 // indirect
github.com/satori/go.uuid v1.2.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/afero v1.8.1 // indirect github.com/spf13/afero v1.8.1 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect

32
go.sum
View File

@ -203,6 +203,24 @@ github.com/dop251/goja v0.0.0-20211129110639-4739a1d10a51/go.mod h1:R9ET47fwRVRP
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d h1:W1n4DvpzZGOISgp7wWNtraLcHtnmnTwBlJidqtMIuwQ= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d h1:W1n4DvpzZGOISgp7wWNtraLcHtnmnTwBlJidqtMIuwQ=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc h1:AuzYp98IFVOi0NU/WcZyGDQ6vAh/zkCjxGD3kt8aLzA=
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 h1:Mg7pY7kxDQD2Bkvr1N+XW4BESSIQ7tTTR7Vv+Gi2CsM=
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb h1:gwjJjUr6FY7zAWVEueFPrcRHhd9+IK81TcItbqw2du4=
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 h1:ULCSN6v0WISNbALxomGPXh4dSjRKPW+7+seYoMz8UTc=
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2/go.mod h1:ZoOP3yUG0HD1T4IUjIFsz/2OAB2yB4YX6NSm4K+uJRg=
github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d h1:F/7L5wr/fP/SKeO5HuMlNEX9Ipyx2MbH2rV9G4zJRpk=
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c h1:7j5aWACOzROpr+dvMtu8GnI97g9ShLWD72XIELMgn+c=
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 h1:RdwKOEEe2ND/JmoKh6I/EQlR9idKJTDOMffPFK6vN2M=
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82/go.mod h1:aDYQkL/5gfRNZkoxiLTSWU4Y8/gV/4MVsy/MU9uwTak=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME=
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a h1:mKoV2b/J8sVVvc6jCl7SxdOrED5cHKdQaHUxjoO5W74= github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a h1:mKoV2b/J8sVVvc6jCl7SxdOrED5cHKdQaHUxjoO5W74=
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ= github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -256,8 +274,9 @@ github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -286,6 +305,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
@ -309,6 +330,9 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc=
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
@ -434,6 +458,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1 h1:p5m7GOEGXyoq6QWl4/RRMsQ6tWbTpbQmAnkxXgWSprY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1 h1:p5m7GOEGXyoq6QWl4/RRMsQ6tWbTpbQmAnkxXgWSprY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1/go.mod h1:8ZeZajTed/blCOHBbj8Fss8bPHiFKcmJJzuIbUtFCAo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1/go.mod h1:8ZeZajTed/blCOHBbj8Fss8bPHiFKcmJJzuIbUtFCAo=
github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4=
github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
@ -535,6 +561,7 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@ -870,6 +897,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 h1:1SWXcTphBQjYGWRRxLFIAR1LVtQEj4eR7xPtyeOVM/c=
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203/go.mod h1:0Xw5cYMOYpgaWs+OOSx41ugycl2qvKTi9tlMMcZhFyY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
@ -1073,6 +1102,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=

View File

@ -1,8 +1,10 @@
package assets package assets
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv" "strconv"
@ -11,6 +13,7 @@ import (
"github.com/caos/logging" "github.com/caos/logging"
sentryhttp "github.com/getsentry/sentry-go/http" sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/superseriousbusiness/exifremove/pkg/exifremove"
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
http_mw "github.com/caos/zitadel/internal/api/http/middleware" http_mw "github.com/caos/zitadel/internal/api/http/middleware"
@ -136,7 +139,13 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError) s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
return return
} }
info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, file, size) cleanedFile, cleanedSize, err := removeExif(file, size, contentType)
if err != nil {
s.ErrorHandler()(w, r, fmt.Errorf("remove exif error: %v", err), http.StatusInternalServerError)
return
}
info, err := s.Commands().UploadAsset(ctx, bucketName, objectName, contentType, cleanedFile, cleanedSize)
if err != nil { if err != nil {
s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError) s.ErrorHandler()(w, r, fmt.Errorf("upload failed: %v", err), http.StatusInternalServerError)
return return
@ -191,3 +200,25 @@ func DownloadHandleFunc(s AssetsService, downloader Downloader) func(http.Respon
w.Write(data) w.Write(data)
} }
} }
func removeExif(file io.Reader, size int64, contentType string) (io.Reader, int64, error) {
if !isAllowedContentType(contentType) {
return file, size, nil
}
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(file)
if err != nil {
return file, 0, err
}
data, err := exifremove.Remove(buf.Bytes())
if err != nil {
return nil, 0, err
}
return bytes.NewReader(data), int64(len(data)), nil
}
func isAllowedContentType(contentType string) bool {
return strings.HasSuffix(contentType, "png") ||
strings.HasSuffix(contentType, "jpg") ||
strings.HasSuffix(contentType, "jpeg")
}

View File

@ -9,5 +9,6 @@ func UpdatePrivacyPolicyToDomain(req *admin_pb.UpdatePrivacyPolicyRequest) *doma
return &domain.PrivacyPolicy{ return &domain.PrivacyPolicy{
TOSLink: req.TosLink, TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink, PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
} }
} }

View File

@ -11,7 +11,7 @@ import (
) )
func (s *Server) ListMyZitadelPermissions(ctx context.Context, _ *auth_pb.ListMyZitadelPermissionsRequest) (*auth_pb.ListMyZitadelPermissionsResponse, error) { func (s *Server) ListMyZitadelPermissions(ctx context.Context, _ *auth_pb.ListMyZitadelPermissionsRequest) (*auth_pb.ListMyZitadelPermissionsResponse, error) {
perms, err := s.query.MyZitadelPermissions(ctx, authz.GetCtxData(ctx).UserID) perms, err := s.query.MyZitadelPermissions(ctx, authz.GetCtxData(ctx).OrgID, authz.GetCtxData(ctx).UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -168,6 +168,7 @@ func (s *Server) ListMyProjectOrgs(ctx context.Context, req *auth_pb.ListMyProje
if err != nil { if err != nil {
return nil, err return nil, err
} }
grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}}) grants, err := s.query.UserGrants(ctx, &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantProjectID, userGrantUserID}})
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,6 +9,7 @@ func AddPrivacyPolicyToDomain(req *mgmt_pb.AddCustomPrivacyPolicyRequest) *domai
return &domain.PrivacyPolicy{ return &domain.PrivacyPolicy{
TOSLink: req.TosLink, TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink, PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
} }
} }
@ -16,5 +17,6 @@ func UpdatePrivacyPolicyToDomain(req *mgmt_pb.UpdateCustomPrivacyPolicyRequest)
return &domain.PrivacyPolicy{ return &domain.PrivacyPolicy{
TOSLink: req.TosLink, TOSLink: req.TosLink,
PrivacyLink: req.PrivacyLink, PrivacyLink: req.PrivacyLink,
HelpLink: req.HelpLink,
} }
} }

View File

@ -126,11 +126,6 @@ func ListProjectGrantMembersRequestToModel(ctx context.Context, req *mgmt_pb.Lis
if err != nil { if err != nil {
return nil, err return nil, err
} }
ownerQuery, err := query.NewMemberResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
queries = append(queries, ownerQuery)
return &query.ProjectGrantMembersQuery{ return &query.ProjectGrantMembersQuery{
MembersQuery: query.MembersQuery{ MembersQuery: query.MembersQuery{
SearchRequest: query.SearchRequest{ SearchRequest: query.SearchRequest{
@ -143,6 +138,7 @@ func ListProjectGrantMembersRequestToModel(ctx context.Context, req *mgmt_pb.Lis
}, },
ProjectID: req.ProjectId, ProjectID: req.ProjectId,
GrantID: req.GrantId, GrantID: req.GrantId,
OrgID: authz.GetCtxData(ctx).OrgID,
}, nil }, nil
} }

View File

@ -88,7 +88,7 @@ func OrgToPb(org *query.Org) *org_pb.Org {
Id: org.ID, Id: org.ID,
Name: org.Name, Name: org.Name,
PrimaryDomain: org.Domain, PrimaryDomain: org.Domain,
Details: object.AddToDetailsPb(org.Sequence, org.CreationDate, org.ResourceOwner), Details: object.ToViewDetailsPb(org.Sequence, org.CreationDate, org.ChangeDate, org.ResourceOwner),
State: OrgStateToPb(org.State), State: OrgStateToPb(org.State),
} }
} }

View File

@ -11,6 +11,7 @@ func ModelPrivacyPolicyToPb(policy *query.PrivacyPolicy) *policy_pb.PrivacyPolic
IsDefault: policy.IsDefault, IsDefault: policy.IsDefault,
TosLink: policy.TOSLink, TosLink: policy.TOSLink,
PrivacyLink: policy.PrivacyLink, PrivacyLink: policy.PrivacyLink,
HelpLink: policy.HelpLink,
Details: object.ToViewDetailsPb( Details: object.ToViewDetailsPb(
policy.Sequence, policy.Sequence,
policy.CreationDate, policy.CreationDate,

View File

@ -457,7 +457,6 @@ func FooterTextToPb(text domain.FooterText) *text_pb.FooterText {
Tos: text.TOS, Tos: text.TOS,
PrivacyPolicy: text.PrivacyPolicy, PrivacyPolicy: text.PrivacyPolicy,
Help: text.Help, Help: text.Help,
HelpLink: text.HelpLink,
} }
} }
@ -947,6 +946,5 @@ func FooterTextPbToDomain(text *text_pb.FooterText) domain.FooterText {
TOS: text.Tos, TOS: text.Tos,
PrivacyPolicy: text.PrivacyPolicy, PrivacyPolicy: text.PrivacyPolicy,
Help: text.Help, Help: text.Help,
HelpLink: text.HelpLink,
} }
} }

View File

@ -37,6 +37,7 @@ func UserGrantToPb(assetPrefix string, grant *query.UserGrant) *user_pb.UserGran
OrgName: grant.OrgName, OrgName: grant.OrgName,
ProjectName: grant.ProjectName, ProjectName: grant.ProjectName,
AvatarUrl: domain.AvatarURL(assetPrefix, grant.UserResourceOwner, grant.AvatarURL), AvatarUrl: domain.AvatarURL(assetPrefix, grant.UserResourceOwner, grant.AvatarURL),
PreferredLoginName: grant.PreferredLoginName,
Details: object.ToViewDetailsPb( Details: object.ToViewDetailsPb(
grant.Sequence, grant.Sequence,
grant.CreationDate, grant.CreationDate,

View File

@ -95,7 +95,7 @@ func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest)
applicationID = authReq.ApplicationID applicationID = authReq.ApplicationID
userOrgID = authReq.UserOrgID userOrgID = authReq.UserOrgID
} }
resp, err := o.command.AddUserToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client resp, err := o.command.AddUserToken(setContextUserSystem(ctx), userOrgID, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
if err != nil { if err != nil {
return "", time.Time{}, err return "", time.Time{}, err
} }
@ -123,7 +123,7 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok
if request, ok := req.(op.RefreshTokenRequest); ok { if request, ok := req.(op.RefreshTokenRequest); ok {
request.SetCurrentScopes(scopes) request.SetCurrentScopes(scopes)
} }
resp, token, err := o.command.AddAccessAndRefreshToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(), resp, token, err := o.command.AddAccessAndRefreshToken(setContextUserSystem(ctx), userOrgID, userAgentID, applicationID, req.GetSubject(),
refreshToken, req.GetAudience(), scopes, authMethodsReferences, o.defaultAccessTokenLifetime, refreshToken, req.GetAudience(), scopes, authMethodsReferences, o.defaultAccessTokenLifetime,
o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client
if err != nil { if err != nil {
@ -171,7 +171,10 @@ func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID strin
if len(userIDs) == 0 { if len(userIDs) == 0 {
return nil return nil
} }
err = o.command.HumansSignOut(ctx, userAgentID, userIDs) data := authz.CtxData{
UserID: userID,
}
err = o.command.HumansSignOut(authz.SetCtxData(ctx, data), userAgentID, userIDs)
logging.Log("OIDC-Dggt2").OnError(err).Error("error signing out") logging.Log("OIDC-Dggt2").OnError(err).Error("error signing out")
return err return err
} }
@ -255,3 +258,10 @@ func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.T
} }
return nil return nil
} }
func setContextUserSystem(ctx context.Context) context.Context {
data := authz.CtxData{
UserID: "SYSTEM",
}
return authz.SetCtxData(ctx, data)
}

View File

@ -203,7 +203,7 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
} }
instanceID := authz.GetInstance(r.Context()).ID instanceID := authz.GetInstance(r.Context()).ID
err = l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, userAgentID, instanceID, externalUser, domain.BrowserInfoFromRequest(r)) err = l.authRepo.CheckExternalUserLogin(setContext(r.Context(), ""), authReq.ID, userAgentID, instanceID, externalUser, domain.BrowserInfoFromRequest(r))
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
err = nil err = nil

View File

@ -84,7 +84,7 @@ func (l *Login) handleJWTExtraction(w http.ResponseWriter, r *http.Request, auth
return return
} }
metadata := externalUser.Metadatas metadata := externalUser.Metadatas
err = l.authRepo.CheckExternalUserLogin(r.Context(), authReq.ID, authReq.AgentID, authReq.InstanceID, externalUser, domain.BrowserInfoFromRequest(r)) err = l.authRepo.CheckExternalUserLogin(setContext(r.Context(), ""), authReq.ID, authReq.AgentID, authReq.InstanceID, externalUser, domain.BrowserInfoFromRequest(r))
if err != nil { if err != nil {
l.jwtExtractionUserNotFound(w, r, authReq, idpConfig, tokens, err) l.jwtExtractionUserNotFound(w, r, authReq, idpConfig, tokens, err)
return return

View File

@ -16,6 +16,7 @@ import (
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n" "github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/renderer" "github.com/caos/zitadel/internal/renderer"
"github.com/caos/zitadel/internal/static" "github.com/caos/zitadel/internal/static"
) )
@ -30,6 +31,10 @@ type Renderer struct {
staticStorage static.Storage staticStorage static.Storage
} }
type LanguageData struct {
Lang string
}
func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage static.Storage, cookieName string, defaultLanguage language.Tag) *Renderer { func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage static.Storage, cookieName string, defaultLanguage language.Tag) *Renderer {
r := &Renderer{ r := &Renderer{
pathPrefix: pathPrefix, pathPrefix: pathPrefix,
@ -345,24 +350,23 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title
CSRF: csrf.TemplateField(r), CSRF: csrf.TemplateField(r),
Nonce: http_mw.GetNonce(r), Nonce: http_mw.GetNonce(r),
} }
var privacyPolicy *domain.PrivacyPolicy
if authReq != nil { if authReq != nil {
baseData.LoginPolicy = authReq.LoginPolicy baseData.LoginPolicy = authReq.LoginPolicy
baseData.LabelPolicy = authReq.LabelPolicy baseData.LabelPolicy = authReq.LabelPolicy
baseData.IDPProviders = authReq.AllowedExternalIDPs baseData.IDPProviders = authReq.AllowedExternalIDPs
if authReq.PrivacyPolicy != nil { if authReq.PrivacyPolicy == nil {
baseData.TOSLink = authReq.PrivacyPolicy.TOSLink return baseData
baseData.PrivacyLink = authReq.PrivacyPolicy.PrivacyLink
} }
privacyPolicy = authReq.PrivacyPolicy
} else { } else {
privacyPolicy, err := l.query.DefaultPrivacyPolicy(r.Context()) policy, err := l.query.DefaultPrivacyPolicy(r.Context())
if err != nil { if err != nil {
return baseData return baseData
} }
if privacyPolicy != nil { privacyPolicy = policy.ToDomain()
baseData.TOSLink = privacyPolicy.TOSLink
baseData.PrivacyLink = privacyPolicy.PrivacyLink
}
} }
baseData = l.setLinksOnBaseData(baseData, privacyPolicy)
return baseData return baseData
} }
@ -392,6 +396,26 @@ func (l *Login) getProfileData(authReq *domain.AuthRequest) profileData {
} }
} }
func (l *Login) setLinksOnBaseData(baseData baseData, privacyPolicy *domain.PrivacyPolicy) baseData {
lang := LanguageData{
Lang: baseData.Lang,
}
baseData.TOSLink = privacyPolicy.TOSLink
baseData.PrivacyLink = privacyPolicy.PrivacyLink
baseData.HelpLink = privacyPolicy.HelpLink
if link, err := templates.ParseTemplateText(privacyPolicy.TOSLink, lang); err == nil {
baseData.TOSLink = link
}
if link, err := templates.ParseTemplateText(privacyPolicy.PrivacyLink, lang); err == nil {
baseData.PrivacyLink = link
}
if link, err := templates.ParseTemplateText(privacyPolicy.HelpLink, lang); err == nil {
baseData.HelpLink = link
}
return baseData
}
func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string) { func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string) {
caosErr := new(caos_errs.CaosError) caosErr := new(caos_errs.CaosError)
if errors.As(err, &caosErr) { if errors.As(err, &caosErr) {
@ -519,6 +543,7 @@ type baseData struct {
DisplayLoginNameSuffix bool DisplayLoginNameSuffix bool
TOSLink string TOSLink string
PrivacyLink string PrivacyLink string
HelpLink string
AuthReqID string AuthReqID string
CSRF template.HTML CSRF template.HTML
Nonce string Nonce string

View File

@ -297,7 +297,6 @@ Footer:
Tos: AGB Tos: AGB
PrivacyPolicy: Datenschutzerklärung PrivacyPolicy: Datenschutzerklärung
Help: Hilfe Help: Hilfe
HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors: Errors:
Internal: Es ist ein interner Fehler aufgetreten Internal: Es ist ein interner Fehler aufgetreten

View File

@ -298,7 +298,6 @@ Footer:
Tos: TOS Tos: TOS
PrivacyPolicy: Privacy policy PrivacyPolicy: Privacy policy
Help: Help Help: Help
HelpLink: https://docs.zitadel.ch/docs/manuals/user-login
Errors: Errors:
Internal: An internal error occured Internal: An internal error occured

View File

@ -298,7 +298,6 @@ Footer:
Tos: Termini di servizio Tos: Termini di servizio
PrivacyPolicy: l'informativa sulla privacy PrivacyPolicy: l'informativa sulla privacy
Help: Aiuto Help: Aiuto
HelpLink: 'https://docs.zitadel.ch/docs/manuals/user-login'
Errors: Errors:
Internal: Si è verificato un errore interno Internal: Si è verificato un errore interno

View File

@ -13,6 +13,8 @@
{{ if .PrivacyLink }} {{ if .PrivacyLink }}
<a href="{{.PrivacyLink}}" rel="noopener noreferrer" target="_blank" alt="Privacy Policy">{{t "Footer.PrivacyPolicy"}}</a> <a href="{{.PrivacyLink}}" rel="noopener noreferrer" target="_blank" alt="Privacy Policy">{{t "Footer.PrivacyPolicy"}}</a>
{{end}} {{end}}
<a href="{{t "Footer.HelpLink"}}" target="_black" alt="Help">{{t "Footer.Help"}}</a> {{ if .HelpLink }}
<a href="{{.HelpLink}}" rel="noopener noreferrer" target="_blank" alt="Help">{{t "Footer.Help"}}</a>
{{end}}
</footer> </footer>
{{end}} {{end}}

View File

@ -560,7 +560,7 @@ func (repo *AuthRequestRepo) fillPolicies(ctx context.Context, request *domain.A
return err return err
} }
request.LockoutPolicy = lockoutPolicyToDomain(lockoutPolicy) request.LockoutPolicy = lockoutPolicyToDomain(lockoutPolicy)
privacyPolicy, err := repo.getPrivacyPolicy(ctx, orgID) privacyPolicy, err := repo.GetPrivacyPolicy(ctx, orgID)
if err != nil { if err != nil {
return err return err
} }
@ -936,8 +936,11 @@ func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView, reques
return checkVerificationTime(user.MFAInitSkipped, request.LoginPolicy.MFAInitSkipLifetime) return checkVerificationTime(user.MFAInitSkipped, request.LoginPolicy.MFAInitSkipLifetime)
} }
func (repo *AuthRequestRepo) getPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) { func (repo *AuthRequestRepo) GetPrivacyPolicy(ctx context.Context, orgID string) (*domain.PrivacyPolicy, error) {
policy, err := repo.PrivacyPolicyProvider.PrivacyPolicyByOrg(ctx, orgID) policy, err := repo.PrivacyPolicyProvider.PrivacyPolicyByOrg(ctx, orgID)
if errors.IsNotFound(err) {
return new(domain.PrivacyPolicy), nil
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -957,6 +960,7 @@ func privacyPolicyToDomain(p *query.PrivacyPolicy) *domain.PrivacyPolicy {
Default: p.IsDefault, Default: p.IsDefault,
TOSLink: p.TOSLink, TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink, PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
} }
} }

View File

@ -4,8 +4,9 @@ import (
"context" "context"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1" v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models" es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query" "github.com/caos/zitadel/internal/eventstore/v1/query"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk" es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
@ -172,19 +173,12 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
} }
func (u *User) fillLoginNames(user *view_model.UserView) (err error) { func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
org, err := u.getOrgByID(context.Background(), user.ResourceOwner) userLoginMustBeDomain, primaryDomain, domains, err := u.loginNameInformation(context.Background(), user.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
policy := new(query2.OrgIAMPolicy) user.SetLoginNames(userLoginMustBeDomain, domains)
if policy == nil { user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
policy, err = u.getDefaultOrgIAMPolicy(context.Background())
if err != nil {
return err
}
}
user.SetLoginNames(policy, org.Domains)
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
return nil return nil
} }
@ -204,40 +198,26 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) {
} }
func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error { func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.getOrgByID(context.Background(), event.ResourceOwner) userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
policy := new(query2.OrgIAMPolicy)
if policy == nil {
policy, err = u.getDefaultOrgIAMPolicy(context.Background())
if err != nil {
return err
}
}
users, err := u.view.UsersByOrgID(event.AggregateID) users, err := u.view.UsersByOrgID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
for _, user := range users { for _, user := range users {
user.SetLoginNames(policy, org.Domains) user.SetLoginNames(userLoginMustBeDomain, domains)
} }
return u.view.PutUsers(users, event) return u.view.PutUsers(users, event)
} }
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error { func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.getOrgByID(context.Background(), event.ResourceOwner) userLoginMustBeDomain, primaryDomain, _, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
policy := new(query2.OrgIAMPolicy) if !userLoginMustBeDomain {
if policy == nil {
policy, err = u.getDefaultOrgIAMPolicy(context.Background())
if err != nil {
return err
}
}
if !policy.UserLoginMustBeDomain {
return nil return nil
} }
users, err := u.view.UsersByOrgID(event.AggregateID) users, err := u.view.UsersByOrgID(event.AggregateID)
@ -245,7 +225,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
return err return err
} }
for _, user := range users { for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain) user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
} }
return u.view.PutUsers(users, event) return u.view.PutUsers(users, event)
} }
@ -281,6 +261,17 @@ func (u *User) getOrgByID(ctx context.Context, orgID string) (*org_model.Org, er
return org_es_model.OrgToModel(esOrg), nil return org_es_model.OrgToModel(esOrg), nil
} }
func (u *User) getDefaultOrgIAMPolicy(ctx context.Context) (*query2.OrgIAMPolicy, error) { func (u *User) loginNameInformation(ctx context.Context, orgID string) (userLoginMustBeDomain bool, primaryDomain string, domains []*org_model.OrgDomain, err error) {
return u.queries.DefaultOrgIAMPolicy(ctx) org, err := u.getOrgByID(ctx, orgID)
if err != nil {
return false, "", nil, err
}
if org.OrgIamPolicy == nil {
policy, err := u.queries.DefaultOrgIAMPolicy(ctx)
if err != nil {
return false, "", nil, err
}
userLoginMustBeDomain = policy.UserLoginMustBeDomain
}
return userLoginMustBeDomain, org.GetPrimaryDomain().Domain, org.Domains, nil
} }

View File

@ -1089,10 +1089,6 @@ func (c *Commands) createFooterTextEvents(ctx context.Context, agg *eventstore.A
if event != nil { if event != nil {
events = append(events, event) events = append(events, event)
} }
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyFooterHelpLink, existingText.FooterHelpLink, text.Footer.HelpLink, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events return events
} }

View File

@ -2508,10 +2508,6 @@ func (wm *CustomLoginTextReadModel) handleFooterTextSetEvent(e *policy.CustomTex
wm.FooterHelp = e.Text wm.FooterHelp = e.Text
return return
} }
if e.Key == domain.LoginKeyFooterHelpLink {
wm.FooterHelpLink = e.Text
return
}
} }
func (wm *CustomLoginTextReadModel) handleFooterTextRemoveEvent(e *policy.CustomTextRemovedEvent) { func (wm *CustomLoginTextReadModel) handleFooterTextRemoveEvent(e *policy.CustomTextRemovedEvent) {
@ -2527,8 +2523,4 @@ func (wm *CustomLoginTextReadModel) handleFooterTextRemoveEvent(e *policy.Custom
wm.FooterHelp = "" wm.FooterHelp = ""
return return
} }
if e.Key == domain.LoginKeyFooterHelpLink {
wm.FooterHelpLink = ""
return
}
} }

View File

@ -130,6 +130,7 @@ func writeModelToPrivacyPolicy(wm *PrivacyPolicyWriteModel) *domain.PrivacyPolic
ObjectRoot: writeModelToObjectRoot(wm.WriteModel), ObjectRoot: writeModelToObjectRoot(wm.WriteModel),
TOSLink: wm.TOSLink, TOSLink: wm.TOSLink,
PrivacyLink: wm.PrivacyLink, PrivacyLink: wm.PrivacyLink,
HelpLink: wm.HelpLink,
} }
} }

View File

@ -1143,11 +1143,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextSetEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
}, },
), ),
), ),
@ -1441,7 +1436,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
TOS: "TOS", TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy", PrivacyPolicy: "PrivacyPolicy",
Help: "Help", Help: "Help",
HelpLink: "HelpLink",
}, },
}, },
}, },
@ -2547,11 +2541,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextSetEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
@ -3645,11 +3634,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
),
),
}, },
), ),
), ),
@ -4797,11 +4781,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextSetEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
eventFromEventPusher( eventFromEventPusher(
iam.NewCustomTextRemovedEvent(context.Background(), iam.NewCustomTextRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English,
@ -5892,11 +5871,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
),
),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
@ -6990,11 +6964,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
iam.NewCustomTextSetEvent(context.Background(),
&iam.NewAggregate().Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
}, },
), ),
), ),
@ -7288,7 +7257,6 @@ func TestCommandSide_SetCustomIAMLoginText(t *testing.T) {
TOS: "TOS", TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy", PrivacyPolicy: "PrivacyPolicy",
Help: "Help", Help: "Help",
HelpLink: "HelpLink",
}, },
}, },
}, },

View File

@ -52,7 +52,7 @@ func (c *Commands) addDefaultPrivacyPolicy(ctx context.Context, iamAgg *eventsto
return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-M00rJ", "Errors.IAM.PrivacyPolicy.AlreadyExists") return nil, caos_errs.ThrowAlreadyExists(nil, "IAM-M00rJ", "Errors.IAM.PrivacyPolicy.AlreadyExists")
} }
return iam_repo.NewPrivacyPolicyAddedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink), nil return iam_repo.NewPrivacyPolicyAddedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink), nil
} }
func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) { func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domain.PrivacyPolicy) (*domain.PrivacyPolicy, error) {
@ -65,7 +65,7 @@ func (c *Commands) ChangeDefaultPrivacyPolicy(ctx context.Context, policy *domai
} }
iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel) iamAgg := IAMAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink) changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, iamAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink)
if !hasChanged { if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged") return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged")
} }

View File

@ -56,7 +56,8 @@ func (wm *IAMPrivacyPolicyWriteModel) NewChangedEvent(
ctx context.Context, ctx context.Context,
aggregate *eventstore.Aggregate, aggregate *eventstore.Aggregate,
tosLink, tosLink,
privacyLink string, privacyLink,
helpLink string,
) (*iam.PrivacyPolicyChangedEvent, bool) { ) (*iam.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0) changes := make([]policy.PrivacyPolicyChanges, 0)
@ -66,6 +67,9 @@ func (wm *IAMPrivacyPolicyWriteModel) NewChangedEvent(
if wm.PrivacyLink != privacyLink { if wm.PrivacyLink != privacyLink {
changes = append(changes, policy.ChangePrivacyLink(privacyLink)) changes = append(changes, policy.ChangePrivacyLink(privacyLink))
} }
if wm.HelpLink != helpLink {
changes = append(changes, policy.ChangeHelpLink(helpLink))
}
if len(changes) == 0 { if len(changes) == 0 {
return nil, false return nil, false
} }

View File

@ -2,6 +2,10 @@ package command
import ( import (
"context" "context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
@ -9,8 +13,6 @@ import (
"github.com/caos/zitadel/internal/eventstore/v1/models" "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/repository/iam" "github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/policy" "github.com/caos/zitadel/internal/repository/policy"
"github.com/stretchr/testify/assert"
"testing"
) )
func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) { func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
@ -42,6 +44,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -52,6 +55,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -71,6 +75,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
}, },
@ -82,6 +87,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -92,6 +98,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
}, },
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
}, },
@ -108,6 +115,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"", "",
"", "",
"",
), ),
), ),
}, },
@ -119,6 +127,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
res: res{ res: res{
@ -129,6 +138,7 @@ func TestCommandSide_AddDefaultPrivacyPolicy(t *testing.T) {
}, },
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
}, },
@ -183,6 +193,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -200,6 +211,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -210,6 +222,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -227,6 +240,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -236,6 +250,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
newDefaultPrivacyPolicyChangedEvent(context.Background(), newDefaultPrivacyPolicyChangedEvent(context.Background(),
"TOSLinkChanged", "TOSLinkChanged",
"PrivacyLinkChanged", "PrivacyLinkChanged",
"HelpLinkChanged",
), ),
), ),
}, },
@ -247,6 +262,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChanged", TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged", PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
}, },
}, },
res: res{ res: res{
@ -257,6 +273,7 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
}, },
TOSLink: "TOSLinkChanged", TOSLink: "TOSLinkChanged",
PrivacyLink: "PrivacyLinkChanged", PrivacyLink: "PrivacyLinkChanged",
HelpLink: "HelpLinkChanged",
}, },
}, },
}, },
@ -280,12 +297,13 @@ func TestCommandSide_ChangeDefaultPrivacyPolicy(t *testing.T) {
} }
} }
func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink string) *iam.PrivacyPolicyChangedEvent { func newDefaultPrivacyPolicyChangedEvent(ctx context.Context, tosLink, privacyLink, helpLink string) *iam.PrivacyPolicyChangedEvent {
event, _ := iam.NewPrivacyPolicyChangedEvent(ctx, event, _ := iam.NewPrivacyPolicyChangedEvent(ctx,
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
[]policy.PrivacyPolicyChanges{ []policy.PrivacyPolicyChanges{
policy.ChangeTOSLink(tosLink), policy.ChangeTOSLink(tosLink),
policy.ChangePrivacyLink(privacyLink), policy.ChangePrivacyLink(privacyLink),
policy.ChangeHelpLink(helpLink),
}, },
) )
return event return event

View File

@ -1161,11 +1161,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextSetEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
}, },
), ),
), ),
@ -1460,7 +1455,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
TOS: "TOS", TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy", PrivacyPolicy: "PrivacyPolicy",
Help: "Help", Help: "Help",
HelpLink: "HelpLink",
}, },
}, },
}, },
@ -2566,11 +2560,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextSetEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
@ -3664,11 +3653,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextRemovedEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
),
),
}, },
), ),
), ),
@ -4816,11 +4800,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextSetEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
eventFromEventPusher( eventFromEventPusher(
org.NewCustomTextRemovedEvent(context.Background(), org.NewCustomTextRemovedEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeySelectAccountTitle, language.English,
@ -5911,11 +5890,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextRemovedEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, language.English,
),
),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
@ -7009,11 +6983,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English, &org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelp, "Help", language.English,
), ),
), ),
eventFromEventPusher(
org.NewCustomTextSetEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate, domain.LoginCustomText, domain.LoginKeyFooterHelpLink, "HelpLink", language.English,
),
),
}, },
), ),
), ),
@ -7308,7 +7277,6 @@ func TestCommandSide_SetCustomOrgLoginText(t *testing.T) {
TOS: "TOS", TOS: "TOS",
PrivacyPolicy: "PrivacyPolicy", PrivacyPolicy: "PrivacyPolicy",
Help: "Help", Help: "Help",
HelpLink: "HelpLink",
}, },
}, },
}, },

View File

@ -5,12 +5,13 @@ import (
"testing" "testing"
"time" "time"
"github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/static/mock"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/caos/zitadel/internal/repository/user"
"github.com/caos/zitadel/internal/static/mock"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore" "github.com/caos/zitadel/internal/eventstore"
@ -266,6 +267,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helpLink",
), ),
), ),
), ),
@ -470,6 +472,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),
@ -686,6 +689,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),
@ -912,6 +916,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),
@ -1203,6 +1208,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),
@ -1420,6 +1426,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),
@ -1684,6 +1691,7 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
&iam.NewAggregate().Aggregate, &iam.NewAggregate().Aggregate,
"toslink", "toslink",
"privacylink", "privacylink",
"helplink",
), ),
), ),
), ),

View File

@ -80,7 +80,7 @@ func (c *Commands) RemoveOrgIAMPolicy(ctx context.Context, orgID string) error {
return err return err
} }
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAM.NotFound") return caos_errs.ThrowNotFound(nil, "ORG-Dvsh3", "Errors.Org.OrgIAMPolicy.NotFound")
} }
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel) orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PolicyOrgIAMWriteModel.WriteModel)

View File

@ -48,7 +48,8 @@ func (c *Commands) AddPrivacyPolicy(ctx context.Context, resourceOwner string, p
ctx, ctx,
orgAgg, orgAgg,
policy.TOSLink, policy.TOSLink,
policy.PrivacyLink)) policy.PrivacyLink,
policy.HelpLink))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -74,7 +75,7 @@ func (c *Commands) ChangePrivacyPolicy(ctx context.Context, resourceOwner string
} }
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel) orgAgg := OrgAggregateFromWriteModel(&existingPolicy.PrivacyPolicyWriteModel.WriteModel)
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.TOSLink, policy.PrivacyLink) changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.TOSLink, policy.PrivacyLink, policy.HelpLink)
if !hasChanged { if !hasChanged {
return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4N9fs", "Errors.Org.PrivacyPolicy.NotChanged") return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4N9fs", "Errors.Org.PrivacyPolicy.NotChanged")
} }

View File

@ -57,7 +57,8 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
ctx context.Context, ctx context.Context,
aggregate *eventstore.Aggregate, aggregate *eventstore.Aggregate,
tosLink, tosLink,
privacyLink string, privacyLink,
helpLink string,
) (*org.PrivacyPolicyChangedEvent, bool) { ) (*org.PrivacyPolicyChangedEvent, bool) {
changes := make([]policy.PrivacyPolicyChanges, 0) changes := make([]policy.PrivacyPolicyChanges, 0)
@ -67,6 +68,9 @@ func (wm *OrgPrivacyPolicyWriteModel) NewChangedEvent(
if wm.PrivacyLink != privacyLink { if wm.PrivacyLink != privacyLink {
changes = append(changes, policy.ChangePrivacyLink(privacyLink)) changes = append(changes, policy.ChangePrivacyLink(privacyLink))
} }
if wm.HelpLink != helpLink {
changes = append(changes, policy.ChangeHelpLink(helpLink))
}
if len(changes) == 0 { if len(changes) == 0 {
return nil, false return nil, false
} }

View File

@ -46,6 +46,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -63,6 +64,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -74,6 +76,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -93,6 +96,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
}, },
@ -105,6 +109,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -115,6 +120,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
}, },
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
}, },
@ -131,6 +137,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"", "",
"", "",
"",
), ),
), ),
}, },
@ -143,6 +150,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
res: res{ res: res{
@ -153,6 +161,7 @@ func TestCommandSide_AddPrivacyPolicy(t *testing.T) {
}, },
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
}, },
@ -207,6 +216,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -227,6 +237,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -244,6 +255,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -255,6 +267,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLink", TOSLink: "TOSLink",
PrivacyLink: "PrivacyLink", PrivacyLink: "PrivacyLink",
HelpLink: "HelpLink",
}, },
}, },
res: res{ res: res{
@ -272,13 +285,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
eventFromEventPusher( eventFromEventPusher(
newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange"), newPrivacyPolicyChangedEvent(context.Background(), "org1", "TOSLinkChange", "PrivacyLinkChange", "HelpLinkChange"),
), ),
}, },
), ),
@ -290,6 +304,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "TOSLinkChange", TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange", PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
}, },
}, },
res: res{ res: res{
@ -300,6 +315,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
}, },
TOSLink: "TOSLinkChange", TOSLink: "TOSLinkChange",
PrivacyLink: "PrivacyLinkChange", PrivacyLink: "PrivacyLinkChange",
HelpLink: "HelpLinkChange",
}, },
}, },
}, },
@ -314,13 +330,14 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
expectPush( expectPush(
[]*repository.Event{ []*repository.Event{
eventFromEventPusher( eventFromEventPusher(
newPrivacyPolicyChangedEvent(context.Background(), "org1", "", ""), newPrivacyPolicyChangedEvent(context.Background(), "org1", "", "", ""),
), ),
}, },
), ),
@ -332,6 +349,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
policy: &domain.PrivacyPolicy{ policy: &domain.PrivacyPolicy{
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
res: res{ res: res{
@ -342,6 +360,7 @@ func TestCommandSide_ChangePrivacyPolicy(t *testing.T) {
}, },
TOSLink: "", TOSLink: "",
PrivacyLink: "", PrivacyLink: "",
HelpLink: "",
}, },
}, },
}, },
@ -424,6 +443,7 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
&org.NewAggregate("org1", "org1").Aggregate, &org.NewAggregate("org1", "org1").Aggregate,
"TOSLink", "TOSLink",
"PrivacyLink", "PrivacyLink",
"HelpLink",
), ),
), ),
), ),
@ -467,12 +487,13 @@ func TestCommandSide_RemovePrivacyPolicy(t *testing.T) {
} }
} }
func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink string) *org.PrivacyPolicyChangedEvent { func newPrivacyPolicyChangedEvent(ctx context.Context, orgID string, tosLink, privacyLink, helpLink string) *org.PrivacyPolicyChangedEvent {
event, _ := org.NewPrivacyPolicyChangedEvent(ctx, event, _ := org.NewPrivacyPolicyChangedEvent(ctx,
&org.NewAggregate(orgID, orgID).Aggregate, &org.NewAggregate(orgID, orgID).Aggregate,
[]policy.PrivacyPolicyChanges{ []policy.PrivacyPolicyChanges{
policy.ChangeTOSLink(tosLink), policy.ChangeTOSLink(tosLink),
policy.ChangePrivacyLink(privacyLink), policy.ChangePrivacyLink(privacyLink),
policy.ChangeHelpLink(helpLink),
}, },
) )
return event return event

View File

@ -11,6 +11,7 @@ type PrivacyPolicyWriteModel struct {
TOSLink string TOSLink string
PrivacyLink string PrivacyLink string
HelpLink string
State domain.PolicyState State domain.PolicyState
} }
@ -20,6 +21,7 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
case *policy.PrivacyPolicyAddedEvent: case *policy.PrivacyPolicyAddedEvent:
wm.TOSLink = e.TOSLink wm.TOSLink = e.TOSLink
wm.PrivacyLink = e.PrivacyLink wm.PrivacyLink = e.PrivacyLink
wm.HelpLink = e.HelpLink
wm.State = domain.PolicyStateActive wm.State = domain.PolicyStateActive
case *policy.PrivacyPolicyChangedEvent: case *policy.PrivacyPolicyChangedEvent:
if e.PrivacyLink != nil { if e.PrivacyLink != nil {
@ -28,6 +30,9 @@ func (wm *PrivacyPolicyWriteModel) Reduce() error {
if e.TOSLink != nil { if e.TOSLink != nil {
wm.TOSLink = *e.TOSLink wm.TOSLink = *e.TOSLink
} }
if e.HelpLink != nil {
wm.HelpLink = *e.HelpLink
}
case *policy.PrivacyPolicyRemovedEvent: case *policy.PrivacyPolicyRemovedEvent:
wm.State = domain.PolicyStateRemoved wm.State = domain.PolicyStateRemoved
} }

View File

@ -38,7 +38,7 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s
orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, orgID) orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, orgID)
if err != nil { if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.OrgIAM.NotExisting") return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.OrgIAMPolicy.NotExisting")
} }
if err := CheckOrgIAMPolicyForUserName(userName, orgIAMPolicy); err != nil { if err := CheckOrgIAMPolicyForUserName(userName, orgIAMPolicy); err != nil {
@ -188,7 +188,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, existingUser.ResourceOwner) orgIAMPolicy, err := c.getOrgIAMPolicy(ctx, existingUser.ResourceOwner)
if err != nil { if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.OrgIAM.NotExisting") return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-3M9fs", "Errors.Org.OrgIAMPolicy.NotExisting")
} }
var events []eventstore.Command var events []eventstore.Command
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel) userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)

View File

@ -34,7 +34,7 @@ func (c *Commands) AddHuman(ctx context.Context, orgID string, human *domain.Hum
} }
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID) pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil { if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound") return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
} }
events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator) events, addedHuman, err := c.addHuman(ctx, orgID, human, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator)
if err != nil { if err != nil {
@ -63,7 +63,7 @@ func (c *Commands) ImportHuman(ctx context.Context, orgID string, human *domain.
} }
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID) pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil { if err != nil {
return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexity.NotFound") return nil, nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-4N8gs", "Errors.Org.PasswordComplexityPolicy.NotFound")
} }
events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator) events, addedHuman, addedCode, code, err := c.importHuman(ctx, orgID, human, passwordless, orgIAMPolicy, pwPolicy, initCodeGenerator, phoneCodeGenerator, passwordlessCodeGenerator)
if err != nil { if err != nil {
@ -128,7 +128,7 @@ func (c *Commands) RegisterHuman(ctx context.Context, orgID string, human *domai
} }
pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID) pwPolicy, err := c.getOrgPasswordComplexityPolicy(ctx, orgID)
if err != nil { if err != nil {
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexity.NotFound") return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-M5Fsd", "Errors.Org.PasswordComplexityPolicy.NotFound")
} }
loginPolicy, err := c.getOrgLoginPolicy(ctx, orgID) loginPolicy, err := c.getOrgLoginPolicy(ctx, orgID)
if err != nil { if err != nil {

View File

@ -28,7 +28,7 @@ func (c *Commands) AddHumanOTP(ctx context.Context, userID, resourceowner string
orgPolicy, err := c.getOrgIAMPolicy(ctx, org.AggregateID) orgPolicy, err := c.getOrgIAMPolicy(ctx, org.AggregateID)
if err != nil { if err != nil {
logging.Log("COMMAND-y5zv9").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get org policy for loginname") logging.Log("COMMAND-y5zv9").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to get org policy for loginname")
return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.OrgIAM.NotFound") return nil, caos_errs.ThrowPreconditionFailed(err, "COMMAND-8ugTs", "Errors.Org.OrgIAMPolicy.NotFound")
} }
otpWriteModel, err := c.otpWriteModelByID(ctx, userID, resourceowner) otpWriteModel, err := c.otpWriteModelByID(ctx, userID, resourceowner)
if err != nil { if err != nil {

View File

@ -294,7 +294,6 @@ const (
LoginKeyFooterTOS = LoginKeyFooter + "Tos" LoginKeyFooterTOS = LoginKeyFooter + "Tos"
LoginKeyFooterPrivacyPolicy = LoginKeyFooter + "PrivacyPolicy" LoginKeyFooterPrivacyPolicy = LoginKeyFooter + "PrivacyPolicy"
LoginKeyFooterHelp = LoginKeyFooter + "Help" LoginKeyFooterHelp = LoginKeyFooter + "Help"
LoginKeyFooterHelpLink = LoginKeyFooter + "HelpLink"
) )
type CustomLoginText struct { type CustomLoginText struct {
@ -637,7 +636,6 @@ type FooterText struct {
TOS string TOS string
PrivacyPolicy string PrivacyPolicy string
Help string Help string
HelpLink string
} }
type PasswordlessPromptScreenText struct { type PasswordlessPromptScreenText struct {

View File

@ -12,4 +12,5 @@ type PrivacyPolicy struct {
TOSLink string TOSLink string
PrivacyLink string PrivacyLink string
HelpLink string
} }

View File

@ -894,7 +894,4 @@ func footerKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyFooterHelp { if text.Key == domain.LoginKeyFooterHelp {
result.Footer.Help = text.Text result.Footer.Help = text.Text
} }
if text.Key == domain.LoginKeyFooterHelpLink {
result.Footer.HelpLink = text.Text
}
} }

View File

@ -3,14 +3,14 @@ package handler
import ( import (
"context" "context"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/v1" v1 "github.com/caos/zitadel/internal/eventstore/v1"
es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk" es_sdk "github.com/caos/zitadel/internal/eventstore/v1/sdk"
org_view "github.com/caos/zitadel/internal/org/repository/view" org_view "github.com/caos/zitadel/internal/org/repository/view"
query2 "github.com/caos/zitadel/internal/query" query2 "github.com/caos/zitadel/internal/query"
"github.com/caos/logging"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models" es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
"github.com/caos/zitadel/internal/eventstore/v1/query" "github.com/caos/zitadel/internal/eventstore/v1/query"
"github.com/caos/zitadel/internal/eventstore/v1/spooler" "github.com/caos/zitadel/internal/eventstore/v1/spooler"
@ -163,23 +163,16 @@ func (u *NotifyUser) ProcessOrg(event *es_models.Event) (err error) {
} }
func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error { func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.getOrgByID(context.Background(), event.ResourceOwner) userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
policy := new(query2.OrgIAMPolicy)
if policy == nil {
policy, err = u.getDefaultOrgIAMPolicy(context.Background())
if err != nil {
return err
}
}
users, err := u.view.NotifyUsersByOrgID(event.AggregateID) users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
for _, user := range users { for _, user := range users {
user.SetLoginNames(policy, org.Domains) user.SetLoginNames(userLoginMustBeDomain, domains)
err := u.view.PutNotifyUser(user, event) err := u.view.PutNotifyUser(user, event)
if err != nil { if err != nil {
return err return err
@ -189,16 +182,11 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
} }
func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error { func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
org, err := u.getOrgByID(context.Background(), event.ResourceOwner) userLoginMustBeDomain, primaryDomain, _, err := u.loginNameInformation(context.Background(), event.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
if !userLoginMustBeDomain {
policy, err := u.getDefaultOrgIAMPolicy(context.Background())
if err != nil {
return err
}
if !policy.UserLoginMustBeDomain {
return nil return nil
} }
users, err := u.view.NotifyUsersByOrgID(event.AggregateID) users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
@ -206,7 +194,7 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e
return err return err
} }
for _, user := range users { for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain) user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
err := u.view.PutNotifyUser(user, event) err := u.view.PutNotifyUser(user, event)
if err != nil { if err != nil {
return err return err
@ -216,17 +204,12 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e
} }
func (u *NotifyUser) fillLoginNames(user *view_model.NotifyUser) (err error) { func (u *NotifyUser) fillLoginNames(user *view_model.NotifyUser) (err error) {
org, err := u.getOrgByID(context.Background(), user.ResourceOwner) userLoginMustBeDomain, primaryDomain, domains, err := u.loginNameInformation(context.Background(), user.ResourceOwner)
if err != nil { if err != nil {
return err return err
} }
user.SetLoginNames(userLoginMustBeDomain, domains)
policy, err := u.getDefaultOrgIAMPolicy(context.Background()) user.PreferredLoginName = user.GenerateLoginName(primaryDomain, userLoginMustBeDomain)
if err != nil {
return err
}
user.SetLoginNames(policy, org.Domains)
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
return nil return nil
} }
@ -261,6 +244,17 @@ func (u *NotifyUser) getOrgByID(ctx context.Context, orgID string) (*org_model.O
return org_es_model.OrgToModel(esOrg), nil return org_es_model.OrgToModel(esOrg), nil
} }
func (u *NotifyUser) getDefaultOrgIAMPolicy(ctx context.Context) (*query2.OrgIAMPolicy, error) { func (u *NotifyUser) loginNameInformation(ctx context.Context, orgID string) (userLoginMustBeDomain bool, primaryDomain string, domains []*org_model.OrgDomain, err error) {
return u.queries.DefaultOrgIAMPolicy(ctx) org, err := u.getOrgByID(ctx, orgID)
if err != nil {
return false, "", nil, err
}
if org.OrgIamPolicy == nil {
policy, err := u.queries.DefaultOrgIAMPolicy(ctx)
if err != nil {
return false, "", nil, err
}
userLoginMustBeDomain = policy.UserLoginMustBeDomain
}
return userLoginMustBeDomain, org.GetPrimaryDomain().Domain, org.Domains, nil
} }

View File

@ -1101,7 +1101,4 @@ func footerKeyToDomain(text *CustomText, result *domain.CustomLoginText) {
if text.Key == domain.LoginKeyFooterHelp { if text.Key == domain.LoginKeyFooterHelp {
result.Footer.Help = text.Text result.Footer.Help = text.Text
} }
if text.Key == domain.LoginKeyFooterHelpLink {
result.Footer.HelpLink = text.Text
}
} }

View File

@ -24,6 +24,7 @@ type PrivacyPolicy struct {
TOSLink string TOSLink string
PrivacyLink string PrivacyLink string
HelpLink string
IsDefault bool IsDefault bool
} }
@ -64,6 +65,10 @@ var (
name: projection.PrivacyPolicyTOSLinkCol, name: projection.PrivacyPolicyTOSLinkCol,
table: privacyTable, table: privacyTable,
} }
PrivacyColHelpLink = Column{
name: projection.PrivacyPolicyHelpLinkCol,
table: privacyTable,
}
PrivacyColIsDefault = Column{ PrivacyColIsDefault = Column{
name: projection.PrivacyPolicyIsDefaultCol, name: projection.PrivacyPolicyIsDefaultCol,
table: privacyTable, table: privacyTable,
@ -125,6 +130,7 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
PrivacyColResourceOwner.identifier(), PrivacyColResourceOwner.identifier(),
PrivacyColPrivacyLink.identifier(), PrivacyColPrivacyLink.identifier(),
PrivacyColTOSLink.identifier(), PrivacyColTOSLink.identifier(),
PrivacyColHelpLink.identifier(),
PrivacyColIsDefault.identifier(), PrivacyColIsDefault.identifier(),
PrivacyColState.identifier(), PrivacyColState.identifier(),
). ).
@ -139,6 +145,7 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
&policy.ResourceOwner, &policy.ResourceOwner,
&policy.PrivacyLink, &policy.PrivacyLink,
&policy.TOSLink, &policy.TOSLink,
&policy.HelpLink,
&policy.IsDefault, &policy.IsDefault,
&policy.State, &policy.State,
) )
@ -151,3 +158,12 @@ func preparePrivacyPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*PrivacyPoli
return policy, nil return policy, nil
} }
} }
func (p *PrivacyPolicy) ToDomain() *domain.PrivacyPolicy {
return &domain.PrivacyPolicy{
TOSLink: p.TOSLink,
PrivacyLink: p.PrivacyLink,
HelpLink: p.HelpLink,
Default: p.IsDefault,
}
}

View File

@ -35,6 +35,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+ ` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+ ` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+ ` projections.privacy_policies.tos_link,`+
` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+ ` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+ ` projections.privacy_policies.state`+
` FROM projections.privacy_policies`), ` FROM projections.privacy_policies`),
@ -43,7 +44,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
), ),
err: func(err error) (error, bool) { err: func(err error) (error, bool) {
if !errs.IsNotFound(err) { if !errs.IsNotFound(err) {
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false return fmt.Errorf("err should be NotFoundError got: %w", err), false
} }
return nil, true return nil, true
}, },
@ -62,6 +63,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+ ` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+ ` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+ ` projections.privacy_policies.tos_link,`+
` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+ ` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+ ` projections.privacy_policies.state`+
` FROM projections.privacy_policies`), ` FROM projections.privacy_policies`),
@ -73,6 +75,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
"resource_owner", "resource_owner",
"privacy_link", "privacy_link",
"tos_link", "tos_link",
"help_link",
"is_default", "is_default",
"state", "state",
}, },
@ -84,6 +87,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
"ro", "ro",
"privacy.ch", "privacy.ch",
"tos.ch", "tos.ch",
"help.ch",
true, true,
domain.PolicyStateActive, domain.PolicyStateActive,
}, },
@ -98,6 +102,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
State: domain.PolicyStateActive, State: domain.PolicyStateActive,
PrivacyLink: "privacy.ch", PrivacyLink: "privacy.ch",
TOSLink: "tos.ch", TOSLink: "tos.ch",
HelpLink: "help.ch",
IsDefault: true, IsDefault: true,
}, },
}, },
@ -113,6 +118,7 @@ func Test_PrivacyPolicyPrepares(t *testing.T) {
` projections.privacy_policies.resource_owner,`+ ` projections.privacy_policies.resource_owner,`+
` projections.privacy_policies.privacy_link,`+ ` projections.privacy_policies.privacy_link,`+
` projections.privacy_policies.tos_link,`+ ` projections.privacy_policies.tos_link,`+
` projections.privacy_policies.help_link,`+
` projections.privacy_policies.is_default,`+ ` projections.privacy_policies.is_default,`+
` projections.privacy_policies.state`+ ` projections.privacy_policies.state`+
` FROM projections.privacy_policies`), ` FROM projections.privacy_policies`),

View File

@ -58,15 +58,21 @@ var (
type ProjectGrantMembersQuery struct { type ProjectGrantMembersQuery struct {
MembersQuery MembersQuery
ProjectID, GrantID string ProjectID, GrantID, OrgID string
} }
func (q *ProjectGrantMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { func (q *ProjectGrantMembersQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return q.MembersQuery. return q.MembersQuery.
toQuery(query). toQuery(query).
Where(sq.Eq{ Where(sq.And{
sq.Eq{
ProjectGrantMemberProjectID.identifier(): q.ProjectID, ProjectGrantMemberProjectID.identifier(): q.ProjectID,
ProjectGrantMemberGrantID.identifier(): q.GrantID, ProjectGrantMemberGrantID.identifier(): q.GrantID,
},
sq.Or{
sq.Eq{ProjectGrantColumnResourceOwner.identifier(): q.OrgID},
sq.Eq{ProjectGrantColumnGrantedOrgID.identifier(): q.OrgID},
},
}) })
} }
@ -117,6 +123,7 @@ func prepareProjectGrantMembersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Memb
LeftJoin(join(HumanUserIDCol, ProjectGrantMemberUserID)). LeftJoin(join(HumanUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(MachineUserIDCol, ProjectGrantMemberUserID)). LeftJoin(join(MachineUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(LoginNameUserIDCol, ProjectGrantMemberUserID)). LeftJoin(join(LoginNameUserIDCol, ProjectGrantMemberUserID)).
LeftJoin(join(ProjectGrantColumnGrantID, ProjectGrantMemberGrantID)).
Where( Where(
sq.Eq{LoginNameIsPrimaryCol.identifier(): true}, sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
).PlaceholderFormat(sq.Dollar), ).PlaceholderFormat(sq.Dollar),

View File

@ -34,6 +34,8 @@ var (
"ON members.user_id = projections.users_machines.user_id " + "ON members.user_id = projections.users_machines.user_id " +
"LEFT JOIN projections.login_names " + "LEFT JOIN projections.login_names " +
"ON members.user_id = projections.login_names.user_id " + "ON members.user_id = projections.login_names.user_id " +
"LEFT JOIN projections.project_grants " +
"ON members.grant_id = projections.project_grants.grant_id " +
"WHERE projections.login_names.is_primary = $1") "WHERE projections.login_names.is_primary = $1")
projectGrantMembersColumns = []string{ projectGrantMembersColumns = []string{
"creation_date", "creation_date",

View File

@ -76,6 +76,7 @@ func (p *FlowProjection) reduceTriggerActionsSetEventType(event eventstore.Event
[]handler.Condition{ []handler.Condition{
handler.NewCond(FlowTypeCol, e.FlowType), handler.NewCond(FlowTypeCol, e.FlowType),
handler.NewCond(FlowTriggerTypeCol, e.TriggerType), handler.NewCond(FlowTriggerTypeCol, e.TriggerType),
handler.NewCond(FlowResourceOwnerCol, e.Aggregate().ResourceOwner),
}, },
) )
for i, id := range e.ActionIDs { for i, id := range e.ActionIDs {
@ -104,6 +105,7 @@ func (p *FlowProjection) reduceFlowClearedEventType(event eventstore.Event) (*ha
e, e,
[]handler.Condition{ []handler.Condition{
handler.NewCond(FlowTypeCol, e.FlowType), handler.NewCond(FlowTypeCol, e.FlowType),
handler.NewCond(FlowResourceOwnerCol, e.Aggregate().ResourceOwner),
}, },
), nil ), nil
} }

View File

@ -39,10 +39,11 @@ func TestFlowProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (trigger_type = $2)", expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (trigger_type = $2) AND (resource_owner = $3)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
domain.FlowTypeExternalAuthentication, domain.FlowTypeExternalAuthentication,
domain.TriggerTypePostAuthentication, domain.TriggerTypePostAuthentication,
"ro-id",
}, },
}, },
{ {
@ -93,9 +94,10 @@ func TestFlowProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1)", expectedStmt: "DELETE FROM projections.flows_triggers WHERE (flow_type = $1) AND (resource_owner = $2)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
domain.FlowTypeExternalAuthentication, domain.FlowTypeExternalAuthentication,
"ro-id",
}, },
}, },
}, },

View File

@ -26,6 +26,7 @@ const (
PrivacyPolicyInstanceIDCol = "instance_id" PrivacyPolicyInstanceIDCol = "instance_id"
PrivacyPolicyPrivacyLinkCol = "privacy_link" PrivacyPolicyPrivacyLinkCol = "privacy_link"
PrivacyPolicyTOSLinkCol = "tos_link" PrivacyPolicyTOSLinkCol = "tos_link"
PrivacyPolicyHelpLinkCol = "help_link"
) )
type PrivacyPolicyProjection struct { type PrivacyPolicyProjection struct {
@ -48,6 +49,7 @@ func NewPrivacyPolicyProjection(ctx context.Context, config crdb.StatementHandle
crdb.NewColumn(PrivacyPolicyInstanceIDCol, crdb.ColumnTypeText), crdb.NewColumn(PrivacyPolicyInstanceIDCol, crdb.ColumnTypeText),
crdb.NewColumn(PrivacyPolicyPrivacyLinkCol, crdb.ColumnTypeText), crdb.NewColumn(PrivacyPolicyPrivacyLinkCol, crdb.ColumnTypeText),
crdb.NewColumn(PrivacyPolicyTOSLinkCol, crdb.ColumnTypeText), crdb.NewColumn(PrivacyPolicyTOSLinkCol, crdb.ColumnTypeText),
crdb.NewColumn(PrivacyPolicyHelpLinkCol, crdb.ColumnTypeText),
}, },
crdb.NewPrimaryKey(PrivacyPolicyInstanceIDCol, PrivacyPolicyIDCol), crdb.NewPrimaryKey(PrivacyPolicyInstanceIDCol, PrivacyPolicyIDCol),
), ),
@ -114,6 +116,7 @@ func (p *PrivacyPolicyProjection) reduceAdded(event eventstore.Event) (*handler.
handler.NewCol(PrivacyPolicyStateCol, domain.PolicyStateActive), handler.NewCol(PrivacyPolicyStateCol, domain.PolicyStateActive),
handler.NewCol(PrivacyPolicyPrivacyLinkCol, policyEvent.PrivacyLink), handler.NewCol(PrivacyPolicyPrivacyLinkCol, policyEvent.PrivacyLink),
handler.NewCol(PrivacyPolicyTOSLinkCol, policyEvent.TOSLink), handler.NewCol(PrivacyPolicyTOSLinkCol, policyEvent.TOSLink),
handler.NewCol(PrivacyPolicyHelpLinkCol, policyEvent.HelpLink),
handler.NewCol(PrivacyPolicyIsDefaultCol, isDefault), handler.NewCol(PrivacyPolicyIsDefaultCol, isDefault),
handler.NewCol(PrivacyPolicyResourceOwnerCol, policyEvent.Aggregate().ResourceOwner), handler.NewCol(PrivacyPolicyResourceOwnerCol, policyEvent.Aggregate().ResourceOwner),
handler.NewCol(PrivacyPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID), handler.NewCol(PrivacyPolicyInstanceIDCol, policyEvent.Aggregate().InstanceID),
@ -140,6 +143,9 @@ func (p *PrivacyPolicyProjection) reduceChanged(event eventstore.Event) (*handle
if policyEvent.TOSLink != nil { if policyEvent.TOSLink != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyTOSLinkCol, *policyEvent.TOSLink)) cols = append(cols, handler.NewCol(PrivacyPolicyTOSLinkCol, *policyEvent.TOSLink))
} }
if policyEvent.HelpLink != nil {
cols = append(cols, handler.NewCol(PrivacyPolicyHelpLinkCol, *policyEvent.HelpLink))
}
return crdb.NewUpdateStatement( return crdb.NewUpdateStatement(
&policyEvent, &policyEvent,
cols, cols,

View File

@ -30,7 +30,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
org.AggregateType, org.AggregateType,
[]byte(`{ []byte(`{
"tosLink": "http://tos.link", "tosLink": "http://tos.link",
"privacyLink": "http://privacy.link" "privacyLink": "http://privacy.link",
"helpLink": "http://help.link"
}`), }`),
), org.PrivacyPolicyAddedEventMapper), ), org.PrivacyPolicyAddedEventMapper),
}, },
@ -43,7 +44,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
anyArg{}, anyArg{},
@ -52,6 +53,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
domain.PolicyStateActive, domain.PolicyStateActive,
"http://privacy.link", "http://privacy.link",
"http://tos.link", "http://tos.link",
"http://help.link",
false, false,
"ro-id", "ro-id",
"instance-id", "instance-id",
@ -70,7 +72,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
org.AggregateType, org.AggregateType,
[]byte(`{ []byte(`{
"tosLink": "http://tos.link", "tosLink": "http://tos.link",
"privacyLink": "http://privacy.link" "privacyLink": "http://privacy.link",
"helpLink": "http://help.link"
}`), }`),
), org.PrivacyPolicyChangedEventMapper), ), org.PrivacyPolicyChangedEventMapper),
}, },
@ -82,12 +85,13 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link) = ($1, $2, $3, $4) WHERE (id = $5)", expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
"http://privacy.link", "http://privacy.link",
"http://tos.link", "http://tos.link",
"http://help.link",
"agg-id", "agg-id",
}, },
}, },
@ -131,7 +135,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
iam.AggregateType, iam.AggregateType,
[]byte(`{ []byte(`{
"tosLink": "http://tos.link", "tosLink": "http://tos.link",
"privacyLink": "http://privacy.link" "privacyLink": "http://privacy.link",
"helpLink": "http://help.link"
}`), }`),
), iam.PrivacyPolicyAddedEventMapper), ), iam.PrivacyPolicyAddedEventMapper),
}, },
@ -143,7 +148,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", expectedStmt: "INSERT INTO projections.privacy_policies (creation_date, change_date, sequence, id, state, privacy_link, tos_link, help_link, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
anyArg{}, anyArg{},
@ -152,6 +157,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
domain.PolicyStateActive, domain.PolicyStateActive,
"http://privacy.link", "http://privacy.link",
"http://tos.link", "http://tos.link",
"http://help.link",
true, true,
"ro-id", "ro-id",
"instance-id", "instance-id",
@ -170,7 +176,8 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
iam.AggregateType, iam.AggregateType,
[]byte(`{ []byte(`{
"tosLink": "http://tos.link", "tosLink": "http://tos.link",
"privacyLink": "http://privacy.link" "privacyLink": "http://privacy.link",
"helpLink": "http://help.link"
}`), }`),
), iam.PrivacyPolicyChangedEventMapper), ), iam.PrivacyPolicyChangedEventMapper),
}, },
@ -182,12 +189,13 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link) = ($1, $2, $3, $4) WHERE (id = $5)", expectedStmt: "UPDATE projections.privacy_policies SET (change_date, sequence, privacy_link, tos_link, help_link) = ($1, $2, $3, $4, $5) WHERE (id = $6)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),
"http://privacy.link", "http://privacy.link",
"http://tos.link", "http://tos.link",
"http://help.link",
"agg-id", "agg-id",
}, },
}, },

View File

@ -34,6 +34,7 @@ type UserGrant struct {
Email string Email string
DisplayName string DisplayName string
AvatarURL string AvatarURL string
PreferredLoginName string
ResourceOwner string ResourceOwner string
OrgName string OrgName string
@ -255,6 +256,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
HumanEmailCol.identifier(), HumanEmailCol.identifier(),
HumanDisplayNameCol.identifier(), HumanDisplayNameCol.identifier(),
HumanAvatarURLCol.identifier(), HumanAvatarURLCol.identifier(),
LoginNameNameCol.identifier(),
UserGrantResourceOwner.identifier(), UserGrantResourceOwner.identifier(),
OrgColumnName.identifier(), OrgColumnName.identifier(),
@ -268,7 +270,10 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
LeftJoin(join(HumanUserIDCol, UserGrantUserID)). LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)). LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
LeftJoin(join(ProjectColumnID, UserGrantProjectID)). LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
PlaceholderFormat(sq.Dollar), LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
Where(
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
).PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*UserGrant, error) { func(row *sql.Row) (*UserGrant, error) {
g := new(UserGrant) g := new(UserGrant)
@ -282,6 +287,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
email sql.NullString email sql.NullString
displayName sql.NullString displayName sql.NullString
avatarURL sql.NullString avatarURL sql.NullString
preferredLoginName sql.NullString
orgName sql.NullString orgName sql.NullString
orgDomain sql.NullString orgDomain sql.NullString
@ -307,6 +313,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
&email, &email,
&displayName, &displayName,
&avatarURL, &avatarURL,
&preferredLoginName,
&g.ResourceOwner, &g.ResourceOwner,
&orgName, &orgName,
@ -331,6 +338,7 @@ func prepareUserGrantQuery() (sq.SelectBuilder, func(*sql.Row) (*UserGrant, erro
g.Email = email.String g.Email = email.String
g.DisplayName = displayName.String g.DisplayName = displayName.String
g.AvatarURL = avatarURL.String g.AvatarURL = avatarURL.String
g.PreferredLoginName = preferredLoginName.String
g.OrgName = orgName.String g.OrgName = orgName.String
g.OrgPrimaryDomain = orgDomain.String g.OrgPrimaryDomain = orgDomain.String
g.ProjectName = projectName.String g.ProjectName = projectName.String
@ -358,6 +366,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
HumanEmailCol.identifier(), HumanEmailCol.identifier(),
HumanDisplayNameCol.identifier(), HumanDisplayNameCol.identifier(),
HumanAvatarURLCol.identifier(), HumanAvatarURLCol.identifier(),
LoginNameNameCol.identifier(),
UserGrantResourceOwner.identifier(), UserGrantResourceOwner.identifier(),
OrgColumnName.identifier(), OrgColumnName.identifier(),
@ -373,7 +382,10 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
LeftJoin(join(HumanUserIDCol, UserGrantUserID)). LeftJoin(join(HumanUserIDCol, UserGrantUserID)).
LeftJoin(join(OrgColumnID, UserGrantResourceOwner)). LeftJoin(join(OrgColumnID, UserGrantResourceOwner)).
LeftJoin(join(ProjectColumnID, UserGrantProjectID)). LeftJoin(join(ProjectColumnID, UserGrantProjectID)).
PlaceholderFormat(sq.Dollar), LeftJoin(join(LoginNameUserIDCol, UserGrantUserID)).
Where(
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
).PlaceholderFormat(sq.Dollar),
func(rows *sql.Rows) (*UserGrants, error) { func(rows *sql.Rows) (*UserGrants, error) {
userGrants := make([]*UserGrant, 0) userGrants := make([]*UserGrant, 0)
var count uint64 var count uint64
@ -390,6 +402,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
email sql.NullString email sql.NullString
displayName sql.NullString displayName sql.NullString
avatarURL sql.NullString avatarURL sql.NullString
preferredLoginName sql.NullString
orgName sql.NullString orgName sql.NullString
orgDomain sql.NullString orgDomain sql.NullString
@ -415,6 +428,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
&email, &email,
&displayName, &displayName,
&avatarURL, &avatarURL,
&preferredLoginName,
&g.ResourceOwner, &g.ResourceOwner,
&orgName, &orgName,
@ -438,6 +452,7 @@ func prepareUserGrantsQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserGrants, e
g.Email = email.String g.Email = email.String
g.DisplayName = displayName.String g.DisplayName = displayName.String
g.AvatarURL = avatarURL.String g.AvatarURL = avatarURL.String
g.PreferredLoginName = preferredLoginName.String
g.OrgName = orgName.String g.OrgName = orgName.String
g.OrgPrimaryDomain = orgDomain.String g.OrgPrimaryDomain = orgDomain.String
g.ProjectName = projectName.String g.ProjectName = projectName.String

View File

@ -32,6 +32,7 @@ var (
", projections.users_humans.email" + ", projections.users_humans.email" +
", projections.users_humans.display_name" + ", projections.users_humans.display_name" +
", projections.users_humans.avatar_key" + ", projections.users_humans.avatar_key" +
", projections.login_names.login_name" +
", projections.user_grants.resource_owner" + ", projections.user_grants.resource_owner" +
", projections.orgs.name" + ", projections.orgs.name" +
", projections.orgs.primary_domain" + ", projections.orgs.primary_domain" +
@ -41,7 +42,9 @@ var (
" LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" + " LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" +
" LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" + " LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" + " LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" +
" LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id") " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id" +
" LEFT JOIN projections.login_names ON projections.user_grants.user_id = projections.login_names.user_id" +
" WHERE projections.login_names.is_primary = $1")
userGrantCols = []string{ userGrantCols = []string{
"id", "id",
"creation_date", "creation_date",
@ -59,6 +62,7 @@ var (
"email", "email",
"display_name", "display_name",
"avatar_key", "avatar_key",
"login_name",
"resource_owner", //user_grant resource owner "resource_owner", //user_grant resource owner
"name", //org name "name", //org name
"primary_domain", "primary_domain",
@ -82,6 +86,7 @@ var (
", projections.users_humans.email" + ", projections.users_humans.email" +
", projections.users_humans.display_name" + ", projections.users_humans.display_name" +
", projections.users_humans.avatar_key" + ", projections.users_humans.avatar_key" +
", projections.login_names.login_name" +
", projections.user_grants.resource_owner" + ", projections.user_grants.resource_owner" +
", projections.orgs.name" + ", projections.orgs.name" +
", projections.orgs.primary_domain" + ", projections.orgs.primary_domain" +
@ -92,7 +97,9 @@ var (
" LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" + " LEFT JOIN projections.users ON projections.user_grants.user_id = projections.users.id" +
" LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" + " LEFT JOIN projections.users_humans ON projections.user_grants.user_id = projections.users_humans.user_id" +
" LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" + " LEFT JOIN projections.orgs ON projections.user_grants.resource_owner = projections.orgs.id" +
" LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id") " LEFT JOIN projections.projects ON projections.user_grants.project_id = projections.projects.id" +
" LEFT JOIN projections.login_names ON projections.user_grants.user_id = projections.login_names.user_id" +
" WHERE projections.login_names.is_primary = $1")
userGrantsCols = append( userGrantsCols = append(
userGrantCols, userGrantCols,
"count", "count",
@ -152,6 +159,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -177,6 +185,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -208,6 +217,7 @@ func Test_UserGrantPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -233,6 +243,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "", Email: "",
DisplayName: "", DisplayName: "",
AvatarURL: "", AvatarURL: "",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -264,6 +275,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
nil, nil,
nil, nil,
@ -289,6 +301,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "", OrgName: "",
OrgPrimaryDomain: "", OrgPrimaryDomain: "",
@ -320,6 +333,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -345,6 +359,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -352,6 +367,64 @@ func Test_UserGrantPrepares(t *testing.T) {
ProjectName: "", ProjectName: "",
}, },
}, },
{
name: "prepareUserGrantQuery (no loginname) found",
prepare: prepareUserGrantQuery,
want: want{
sqlExpectations: mockQuery(
userGrantStmt,
userGrantCols,
[]driver.Value{
"id",
testNow,
testNow,
20211111,
"grant-id",
pq.StringArray{"role-key"},
domain.UserGrantStateActive,
"user-id",
"username",
domain.UserTypeHuman,
"resource-owner",
"first-name",
"last-name",
"email",
"display-name",
"avatar-key",
nil,
"ro",
"org-name",
"primary-domain",
"project-id",
"project-name",
},
),
},
object: &UserGrant{
ID: "id",
CreationDate: testNow,
ChangeDate: testNow,
Sequence: 20211111,
Roles: []string{"role-key"},
GrantID: "grant-id",
State: domain.UserGrantStateActive,
UserID: "user-id",
Username: "username",
UserType: domain.UserTypeHuman,
UserResourceOwner: "resource-owner",
FirstName: "first-name",
LastName: "last-name",
Email: "email",
DisplayName: "display-name",
AvatarURL: "avatar-key",
PreferredLoginName: "",
ResourceOwner: "ro",
OrgName: "org-name",
OrgPrimaryDomain: "primary-domain",
ProjectID: "project-id",
ProjectName: "project-name",
},
},
{ {
name: "prepareUserGrantQuery sql err", name: "prepareUserGrantQuery sql err",
prepare: prepareUserGrantQuery, prepare: prepareUserGrantQuery,
@ -406,6 +479,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -437,6 +511,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -471,6 +546,7 @@ func Test_UserGrantPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -502,6 +578,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "", Email: "",
DisplayName: "", DisplayName: "",
AvatarURL: "", AvatarURL: "",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -536,6 +613,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
nil, nil,
nil, nil,
@ -567,6 +645,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "", OrgName: "",
OrgPrimaryDomain: "", OrgPrimaryDomain: "",
@ -601,6 +680,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -632,6 +712,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -641,6 +722,73 @@ func Test_UserGrantPrepares(t *testing.T) {
}, },
}, },
}, },
{
name: "prepareUserGrantsQuery one grant (no loginname)",
prepare: prepareUserGrantsQuery,
want: want{
sqlExpectations: mockQueries(
userGrantsStmt,
userGrantsCols,
[][]driver.Value{
{
"id",
testNow,
testNow,
20211111,
"grant-id",
pq.StringArray{"role-key"},
domain.UserGrantStateActive,
"user-id",
"username",
domain.UserTypeHuman,
"resource-owner",
"first-name",
"last-name",
"email",
"display-name",
"avatar-key",
nil,
"ro",
"org-name",
"primary-domain",
"project-id",
"project-name",
},
},
),
},
object: &UserGrants{
SearchResponse: SearchResponse{
Count: 1,
},
UserGrants: []*UserGrant{
{
ID: "id",
CreationDate: testNow,
ChangeDate: testNow,
Sequence: 20211111,
Roles: []string{"role-key"},
GrantID: "grant-id",
State: domain.UserGrantStateActive,
UserID: "user-id",
Username: "username",
UserType: domain.UserTypeHuman,
UserResourceOwner: "resource-owner",
FirstName: "first-name",
LastName: "last-name",
Email: "email",
DisplayName: "display-name",
AvatarURL: "avatar-key",
PreferredLoginName: "",
ResourceOwner: "ro",
OrgName: "org-name",
OrgPrimaryDomain: "primary-domain",
ProjectID: "project-id",
ProjectName: "project-name",
},
},
},
},
{ {
name: "prepareUserGrantsQuery multiple grants", name: "prepareUserGrantsQuery multiple grants",
prepare: prepareUserGrantsQuery, prepare: prepareUserGrantsQuery,
@ -666,6 +814,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -689,6 +838,7 @@ func Test_UserGrantPrepares(t *testing.T) {
"email", "email",
"display-name", "display-name",
"avatar-key", "avatar-key",
"login-name",
"ro", "ro",
"org-name", "org-name",
"primary-domain", "primary-domain",
@ -720,6 +870,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",
@ -743,6 +894,7 @@ func Test_UserGrantPrepares(t *testing.T) {
Email: "email", Email: "email",
DisplayName: "display-name", DisplayName: "display-name",
AvatarURL: "avatar-key", AvatarURL: "avatar-key",
PreferredLoginName: "login-name",
ResourceOwner: "ro", ResourceOwner: "ro",
OrgName: "org-name", OrgName: "org-name",
OrgPrimaryDomain: "primary-domain", OrgPrimaryDomain: "primary-domain",

View File

@ -70,6 +70,14 @@ func NewMembershipOrgIDQuery(value string) (SearchQuery, error) {
return NewTextQuery(membershipOrgID, value, TextEquals) return NewTextQuery(membershipOrgID, value, TextEquals)
} }
func NewMembershipResourceOwnersSearchQuery(ids ...string) (SearchQuery, error) {
list := make([]interface{}, len(ids))
for i, value := range ids {
list[i] = value
}
return NewListQuery(membershipResourceOwner, list, ListIn)
}
func NewMembershipProjectIDQuery(value string) (SearchQuery, error) { func NewMembershipProjectIDQuery(value string) (SearchQuery, error) {
return NewTextQuery(membershipProjectID, value, TextEquals) return NewTextQuery(membershipProjectID, value, TextEquals)
} }

View File

@ -6,13 +6,17 @@ import (
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
) )
func (q *Queries) MyZitadelPermissions(ctx context.Context, userID string) (*domain.Permissions, error) { func (q *Queries) MyZitadelPermissions(ctx context.Context, orgID, userID string) (*domain.Permissions, error) {
userIDQuery, err := NewMembershipUserIDQuery(userID) userIDQuery, err := NewMembershipUserIDQuery(userID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
orgIDsQuery, err := NewMembershipResourceOwnersSearchQuery(orgID, domain.IAMID)
if err != nil {
return nil, err
}
memberships, err := q.Memberships(ctx, &MembershipSearchQuery{ memberships, err := q.Memberships(ctx, &MembershipSearchQuery{
Queries: []SearchQuery{userIDQuery}, Queries: []SearchQuery{userIDQuery, orgIDsQuery},
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -22,7 +22,8 @@ func NewPrivacyPolicyAddedEvent(
ctx context.Context, ctx context.Context,
aggregate *eventstore.Aggregate, aggregate *eventstore.Aggregate,
tosLink, tosLink,
privacyLink string, privacyLink,
helpLink string,
) *PrivacyPolicyAddedEvent { ) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{ return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent( PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@ -31,7 +32,8 @@ func NewPrivacyPolicyAddedEvent(
aggregate, aggregate,
PrivacyPolicyAddedEventType), PrivacyPolicyAddedEventType),
tosLink, tosLink,
privacyLink), privacyLink,
helpLink),
} }
} }

View File

@ -23,7 +23,8 @@ func NewPrivacyPolicyAddedEvent(
ctx context.Context, ctx context.Context,
aggregate *eventstore.Aggregate, aggregate *eventstore.Aggregate,
tosLink, tosLink,
privacyLink string, privacyLink,
helpLink string,
) *PrivacyPolicyAddedEvent { ) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{ return &PrivacyPolicyAddedEvent{
PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent( PrivacyPolicyAddedEvent: *policy.NewPrivacyPolicyAddedEvent(
@ -32,7 +33,8 @@ func NewPrivacyPolicyAddedEvent(
aggregate, aggregate,
PrivacyPolicyAddedEventType), PrivacyPolicyAddedEventType),
tosLink, tosLink,
privacyLink), privacyLink,
helpLink),
} }
} }

View File

@ -20,6 +20,7 @@ type PrivacyPolicyAddedEvent struct {
TOSLink string `json:"tosLink,omitempty"` TOSLink string `json:"tosLink,omitempty"`
PrivacyLink string `json:"privacyLink,omitempty"` PrivacyLink string `json:"privacyLink,omitempty"`
HelpLink string `json:"helpLink,omitempty"`
} }
func (e *PrivacyPolicyAddedEvent) Data() interface{} { func (e *PrivacyPolicyAddedEvent) Data() interface{} {
@ -33,12 +34,14 @@ func (e *PrivacyPolicyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueC
func NewPrivacyPolicyAddedEvent( func NewPrivacyPolicyAddedEvent(
base *eventstore.BaseEvent, base *eventstore.BaseEvent,
tosLink, tosLink,
privacyLink string, privacyLink,
helpLink string,
) *PrivacyPolicyAddedEvent { ) *PrivacyPolicyAddedEvent {
return &PrivacyPolicyAddedEvent{ return &PrivacyPolicyAddedEvent{
BaseEvent: *base, BaseEvent: *base,
TOSLink: tosLink, TOSLink: tosLink,
PrivacyLink: privacyLink, PrivacyLink: privacyLink,
HelpLink: helpLink,
} }
} }
@ -59,6 +62,7 @@ type PrivacyPolicyChangedEvent struct {
TOSLink *string `json:"tosLink,omitempty"` TOSLink *string `json:"tosLink,omitempty"`
PrivacyLink *string `json:"privacyLink,omitempty"` PrivacyLink *string `json:"privacyLink,omitempty"`
HelpLink *string `json:"helpLink,omitempty"`
} }
func (e *PrivacyPolicyChangedEvent) Data() interface{} { func (e *PrivacyPolicyChangedEvent) Data() interface{} {
@ -99,6 +103,12 @@ func ChangePrivacyLink(privacyLink string) func(*PrivacyPolicyChangedEvent) {
} }
} }
func ChangeHelpLink(helpLink string) func(*PrivacyPolicyChangedEvent) {
return func(e *PrivacyPolicyChangedEvent) {
e.HelpLink = &helpLink
}
}
func PrivacyPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) { func PrivacyPolicyChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
e := &PrivacyPolicyChangedEvent{ e := &PrivacyPolicyChangedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),

View File

@ -193,22 +193,22 @@ Errors:
NotChanged: Default Message Text wurde nicht verändert NotChanged: Default Message Text wurde nicht verändert
AlreadyExists: Default Message Text existiert bereits AlreadyExists: Default Message Text existiert bereits
Invalid: Default Message Text ist ungültig Invalid: Default Message Text ist ungültig
PasswordComplexity: PasswordComplexityPolicy:
NotFound: Password Komplexitäts Policy konnte nicht gefunden werden NotFound: Password Komplexitäts Policy konnte nicht gefunden werden
Empty: Passwort Komplexitäts Policy ist leer Empty: Passwort Komplexitäts Policy ist leer
NotExisting: Passwort Komplexitäts Policy existiert nicht NotExisting: Passwort Komplexitäts Policy existiert nicht
AlreadyExists: Passwort Komplexitäts Policy existiert bereits AlreadyExists: Passwort Komplexitäts Policy existiert bereits
PasswordLockout: PasswordLockoutPolicy:
NotFound: Password Lockout Policy konnte nicht gefunden werden NotFound: Password Lockout Policy konnte nicht gefunden werden
Empty: Passwort Lockout Policy ist leer Empty: Passwort Lockout Policy ist leer
NotExisting: Passwort Lockout Policy existiert nicht NotExisting: Passwort Lockout Policy existiert nicht
AlreadyExists: Passwort Lockout Policy existiert bereits AlreadyExists: Passwort Lockout Policy existiert bereits
PasswordAge: PasswordAgePolicy:
NotFound: Password Age Policy konnte nicht gefunden werden NotFound: Password Age Policy konnte nicht gefunden werden
Empty: Passwort Age Policy ist leer Empty: Passwort Age Policy ist leer
NotExisting: Passwort Age Policy existiert nicht NotExisting: Passwort Age Policy existiert nicht
AlreadyExists: Passwort Age Policy existiert bereits AlreadyExists: Passwort Age Policy existiert bereits
OrgIAM: OrgIAMPolicy:
Empty: Org IAM Policy ist leer Empty: Org IAM Policy ist leer
NotExisting: Org IAM Policy existiert nicht NotExisting: Org IAM Policy existiert nicht
AlreadyExists: Org IAM Policy existiert bereits AlreadyExists: Org IAM Policy existiert bereits
@ -589,6 +589,10 @@ EventTypes:
cascade: cascade:
removed: Berechtigung entfernt removed: Berechtigung entfernt
changed: Berechtigung geändert changed: Berechtigung geändert
metadata:
set: Benutzer Metadaten gesetzt
removed: Benutzer Metadaten gelöscht
removed.all: Alle Benutzer Metadaten gelöscht
org: org:
added: Organisation hinzugefügt added: Organisation hinzugefügt
changed: Organisation geändert changed: Organisation geändert

View File

@ -193,22 +193,22 @@ Errors:
NotChanged: Default Message Text has not been changed NotChanged: Default Message Text has not been changed
AlreadyExists: Default Message Text already exists AlreadyExists: Default Message Text already exists
Invalid: Default Message Text is invalid Invalid: Default Message Text is invalid
PasswordComplexity: PasswordComplexityPolicy:
NotFound: Password Complexity Policy not found NotFound: Password Complexity Policy not found
Empty: Password Complexity Policy is empty Empty: Password Complexity Policy is empty
NotExisting: Password Complexity Policy doesn't exist NotExisting: Password Complexity Policy doesn't exist
AlreadyExists: Password Complexity Policy already exists AlreadyExists: Password Complexity Policy already exists
PasswordLockout: PasswordLockoutPolicy:
NotFound: Password Lockout Policy not found NotFound: Password Lockout Policy not found
Empty: Password Lockout Policy is empty Empty: Password Lockout Policy is empty
NotExisting: Password Lockout Policy doesn't exist NotExisting: Password Lockout Policy doesn't exist
AlreadyExists: Password Lockout Policy already exists AlreadyExists: Password Lockout Policy already exists
PasswordAge: PasswordAgePolicy:
NotFound: Password Age Policy not found NotFound: Password Age Policy not found
Empty: Password Age Policy is empty Empty: Password Age Policy is empty
NotExisting: Password Age Policy doesn't exist NotExisting: Password Age Policy doesn't exist
AlreadyExists: Password Age Policy already exists AlreadyExists: Password Age Policy already exists
OrgIAM: OrgIAMPolicy:
Empty: Org IAM Policy is empty Empty: Org IAM Policy is empty
NotExisting: Org IAM Policy doesn't exist NotExisting: Org IAM Policy doesn't exist
AlreadyExists: Org IAM Policy already exists AlreadyExists: Org IAM Policy already exists
@ -589,6 +589,10 @@ EventTypes:
cascade: cascade:
removed: Authorization removed removed: Authorization removed
changed: Authorization changed changed: Authorization changed
metadata:
set: User metadata set
removed: User metadata removed
removed.all: All user metadata removed
org: org:
added: Organization added added: Organization added
changed: Organization changed changed: Organization changed

View File

@ -191,22 +191,22 @@ Errors:
NotChanged: Il testo predefinito non è stato cambiato NotChanged: Il testo predefinito non è stato cambiato
AlreadyExists: Il testo predefinito già eistente AlreadyExists: Il testo predefinito già eistente
Invalid: Il testo predefinito non è valido Invalid: Il testo predefinito non è valido
PasswordComplexity: PasswordComplexityPolicy:
NotFound: Impostazioni di complessità della password non trovati NotFound: Impostazioni di complessità della password non trovati
Empty: Mancano le impostazioni di complessità della password Empty: Mancano le impostazioni di complessità della password
NotExisting: Impostazioni di complessità della password non esistenti NotExisting: Impostazioni di complessità della password non esistenti
AlreadyExists: Impostazioni di complessità della password sono già esistenti AlreadyExists: Impostazioni di complessità della password sono già esistenti
PasswordLockout: PasswordLockoutPolicy:
NotFound: Impostazioni di blocco della password non trovati NotFound: Impostazioni di blocco della password non trovati
Empty: Mancano le impostazioni di blocco della password Empty: Mancano le impostazioni di blocco della password
NotExisting: Le impostazioni di blocco della password non esistenti NotExisting: Le impostazioni di blocco della password non esistenti
AlreadyExists: Le impostazioni di blocco della password sono già esistenti AlreadyExists: Le impostazioni di blocco della password sono già esistenti
PasswordAge: PasswordAgePolicy:
NotFound: Impostazioni di validità della password NotFound: Impostazioni di validità della password
Empty: Impostazioni di validità della password mancanti Empty: Impostazioni di validità della password mancanti
NotExisting: Impostazioni di validità della password non esistenti NotExisting: Impostazioni di validità della password non esistenti
AlreadyExists: Impostazioni di validità della password sono già esistenti AlreadyExists: Impostazioni di validità della password sono già esistenti
OrgIAM: OrgIAMPolicy:
Empty: Mancano le impostazioni Org IAM Empty: Mancano le impostazioni Org IAM
NotExisting: Impostazioni Org IAM non esistenti NotExisting: Impostazioni Org IAM non esistenti
AlreadyExists: Impostazioni Org IAM già esistenti AlreadyExists: Impostazioni Org IAM già esistenti
@ -587,6 +587,10 @@ EventTypes:
cascade: cascade:
removed: Autorizzazione rimossa removed: Autorizzazione rimossa
changed: Autorizzazione cambiata changed: Autorizzazione cambiata
metadata:
set: Set di metadati utente
removed: Metadati utente rimossi
removed.all: Tutti i metadati utente rimossi
org: org:
added: Organizzazione aggiunta added: Organizzazione aggiunta
changed: Organizzazione cambiata changed: Organizzazione cambiata

View File

@ -4,8 +4,6 @@ import (
"encoding/json" "encoding/json"
"time" "time"
"github.com/caos/zitadel/internal/query"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/lib/pq" "github.com/lib/pq"
@ -100,14 +98,14 @@ func (u *NotifyUser) GenerateLoginName(domain string, appendDomain bool) string
return u.UserName + "@" + domain return u.UserName + "@" + domain
} }
func (u *NotifyUser) SetLoginNames(policy *query.OrgIAMPolicy, domains []*org_model.OrgDomain) { func (u *NotifyUser) SetLoginNames(userLoginMustBeDomain bool, domains []*org_model.OrgDomain) {
loginNames := make([]string, 0) loginNames := make([]string, 0)
for _, d := range domains { for _, d := range domains {
if d.Verified { if d.Verified {
loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true)) loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true))
} }
} }
if !policy.UserLoginMustBeDomain { if !userLoginMustBeDomain {
loginNames = append(loginNames, u.UserName) loginNames = append(loginNames, u.UserName)
} }
u.LoginNames = loginNames u.LoginNames = loginNames

View File

@ -8,8 +8,6 @@ import (
"github.com/caos/logging" "github.com/caos/logging"
"github.com/lib/pq" "github.com/lib/pq"
"github.com/caos/zitadel/internal/query"
req_model "github.com/caos/zitadel/internal/auth_request/model" req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
@ -230,14 +228,14 @@ func (u *UserView) GenerateLoginName(domain string, appendDomain bool) string {
return u.UserName + "@" + domain return u.UserName + "@" + domain
} }
func (u *UserView) SetLoginNames(policy *query.OrgIAMPolicy, domains []*org_model.OrgDomain) { func (u *UserView) SetLoginNames(userLoginMustBeDomain bool, domains []*org_model.OrgDomain) {
loginNames := make([]string, 0) loginNames := make([]string, 0)
for _, d := range domains { for _, d := range domains {
if d.Verified { if d.Verified {
loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true)) loginNames = append(loginNames, u.GenerateLoginName(d.Domain, true))
} }
} }
if !policy.UserLoginMustBeDomain { if !userLoginMustBeDomain {
loginNames = append(loginNames, u.UserName) loginNames = append(loginNames, u.UserName)
} }
u.LoginNames = loginNames u.LoginNames = loginNames

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/caos/logging"
"github.com/duo-labs/webauthn/protocol" "github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn" "github.com/duo-labs/webauthn/webauthn"
@ -107,6 +108,8 @@ func (w *WebAuthN) FinishRegistration(user *domain.Human, webAuthN *domain.WebAu
} }
credentialData, err := protocol.ParseCredentialCreationResponseBody(bytes.NewReader(credData)) credentialData, err := protocol.ParseCredentialCreationResponseBody(bytes.NewReader(credData))
if err != nil { if err != nil {
e := *err.(*protocol.Error)
logging.WithFields("error", e).Error("webauthn credential could not be parsed")
return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential") return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential")
} }
sessionData := WebAuthNToSessionData(webAuthN) sessionData := WebAuthNToSessionData(webAuthN)

View File

@ -1771,6 +1771,7 @@ service AdminService {
//Updates the default privacy policy of ZITADEL //Updates the default privacy policy of ZITADEL
// it impacts all organisations without a customised policy // it impacts all organisations without a customised policy
// Variable {{.Lang}} can be set to have different links based on the language
rpc UpdatePrivacyPolicy(UpdatePrivacyPolicyRequest) returns (UpdatePrivacyPolicyResponse) { rpc UpdatePrivacyPolicy(UpdatePrivacyPolicyRequest) returns (UpdatePrivacyPolicyResponse) {
option (google.api.http) = { option (google.api.http) = {
put: "/policies/privacy"; put: "/policies/privacy";
@ -3765,6 +3766,7 @@ message GetPrivacyPolicyResponse {
message UpdatePrivacyPolicyRequest { message UpdatePrivacyPolicyRequest {
string tos_link = 1; string tos_link = 1;
string privacy_link = 2; string privacy_link = 2;
string help_link = 3;
} }
message UpdatePrivacyPolicyResponse { message UpdatePrivacyPolicyResponse {

View File

@ -2133,6 +2133,7 @@ service ManagementService {
// Add a custom privacy policy for the organisation // Add a custom privacy policy for the organisation
// With this policy privacy relevant things can be configured (e.g. tos link) // With this policy privacy relevant things can be configured (e.g. tos link)
// Variable {{.Lang}} can be set to have different links based on the language
rpc AddCustomPrivacyPolicy(AddCustomPrivacyPolicyRequest) returns (AddCustomPrivacyPolicyResponse) { rpc AddCustomPrivacyPolicy(AddCustomPrivacyPolicyRequest) returns (AddCustomPrivacyPolicyResponse) {
option (google.api.http) = { option (google.api.http) = {
post: "/policies/privacy" post: "/policies/privacy"
@ -2147,6 +2148,7 @@ service ManagementService {
// Update the privacy complexity policy for the organisation // Update the privacy complexity policy for the organisation
// With this policy privacy relevant things can be configured (e.g. tos link) // With this policy privacy relevant things can be configured (e.g. tos link)
// Variable {{.Lang}} can be set to have different links based on the language
rpc UpdateCustomPrivacyPolicy(UpdateCustomPrivacyPolicyRequest) returns (UpdateCustomPrivacyPolicyResponse) { rpc UpdateCustomPrivacyPolicy(UpdateCustomPrivacyPolicyRequest) returns (UpdateCustomPrivacyPolicyResponse) {
option (google.api.http) = { option (google.api.http) = {
put: "/policies/privacy" put: "/policies/privacy"
@ -4646,6 +4648,7 @@ message GetDefaultPrivacyPolicyResponse {
message AddCustomPrivacyPolicyRequest { message AddCustomPrivacyPolicyRequest {
string tos_link = 1; string tos_link = 1;
string privacy_link = 2; string privacy_link = 2;
string help_link = 3;
} }
message AddCustomPrivacyPolicyResponse { message AddCustomPrivacyPolicyResponse {
@ -4655,6 +4658,7 @@ message AddCustomPrivacyPolicyResponse {
message UpdateCustomPrivacyPolicyRequest { message UpdateCustomPrivacyPolicyRequest {
string tos_link = 1; string tos_link = 1;
string privacy_link = 2; string privacy_link = 2;
string help_link = 3;
} }
message UpdateCustomPrivacyPolicyResponse { message UpdateCustomPrivacyPolicyResponse {

View File

@ -229,4 +229,5 @@ message PrivacyPolicy {
string tos_link = 2; string tos_link = 2;
string privacy_link = 3; string privacy_link = 3;
bool is_default = 4; bool is_default = 4;
string help_link = 5;
} }

View File

@ -382,12 +382,11 @@ message LogoutDoneScreenText {
} }
message FooterText { message FooterText {
reserved 2, 4; reserved 2, 4, 6;
reserved "tos_link", "privacy_policy_link"; reserved "tos_link", "privacy_policy_link", "help_link";
string tos = 1 [(validate.rules).string = {max_len: 200}]; string tos = 1 [(validate.rules).string = {max_len: 200}];
string privacy_policy = 3 [(validate.rules).string = {max_len: 200}]; string privacy_policy = 3 [(validate.rules).string = {max_len: 200}];
string help = 5 [(validate.rules).string = {max_len: 200}]; string help = 5 [(validate.rules).string = {max_len: 200}];
string help_link = 6 [(validate.rules).string = {max_len: 500}];
} }
message PasswordlessPromptScreenText { message PasswordlessPromptScreenText {

View File

@ -681,6 +681,11 @@ message UserGrant {
example: "\"https://api.zitadel.ch/assets/v1/avatar-32432jkh4kj32\""; example: "\"https://api.zitadel.ch/assets/v1/avatar-32432jkh4kj32\"";
} }
]; ];
string preferred_login_name = 18 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"gigi@caos.ch\"";
}
];
} }
enum UserGrantState { enum UserGrantState {