fix(console): clear storage entry if org is unknown, use zitadel as storage prefix, prettier domain verification (#836)

* fix: intercept wrong org id, zitadel as prefix

* rm constructor

* lint interceptor

* improve verification dialog

* refactor domain verification i18n

* reference preview img
This commit is contained in:
Max Peintner 2020-10-21 11:26:58 +02:00 committed by GitHub
parent b3f68c8f48
commit efcac8e70a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 53 deletions

View File

@ -1,47 +1,54 @@
<span class="title" mat-dialog-title>{{domain.domain}} {{'ORG.PAGES.ORGDOMAIN_TITLE' | translate}} </span>
<span class="title" mat-dialog-title>{{'ORG.PAGES.ORGDOMAIN.TITLE' | translate}} {{domain.domain}}</span>
<div mat-dialog-content>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate }}</p>
<p class="desc warn">{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_VALIDATION_DESC' | translate }}</p>
<p class="desc warn">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_DESC' | translate }}</p>
<p *ngIf="domain.validationType !== OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_UNSPECIFIED" class="desc">
{{'ORG.PAGES.ORGDOMAIN_VERIFICATION_VALIDATION_ONGOING' | translate: domain }}</p>
{{'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING' | translate: domain }}
{{'ORG.PAGES.ORGDOMAIN.VERIFICATION_VALIDATION_ONGOING_TYPE' | translate}}
{{'ORG.PAGES.ORGDOMAIN.TYPES.'+ domain.validationType | translate}}</p>
<div *ngIf="domain.validationType !== OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_UNSPECIFIED"
class="btn-container">
<button color="primary" type="submit" mat-raised-button
(click)="validate()">{{ 'ACTIONS.VERIFY' | translate }}</button>
<button *ngIf="!showNew" mat-stroked-button color="primary"
(click)="showNew = true">{{'ORG.PAGES.ORGDOMAIN.REQUESTNEWTOKEN' | translate}}</button>
</div>
<p>{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE' | translate }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC' | translate }}</p>
<ng-container *ngIf="showNew">
<p>{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_NEWTOKEN_TITLE' | translate }}</p>
<p class="desc">{{ 'ORG.PAGES.ORGDOMAIN.VERIFICATION_NEWTOKEN_DESC' | translate }}</p>
<div class="btn-container" *ngIf="!(http || dns)">
<button color="primary" mat-raised-button (click)="loadHttpToken()">HTTP</button>
<button color="primary" mat-raised-button (click)="loadDnsToken()">DNS</button>
</div>
<div *ngIf="http">
<p>HTTP TOKEN</p>
<p class="entry">{{http?.url}}.txt</p>
<div class="btn-container">
<button mat-stroked-button (click)="saveFile()"
color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
<div class="btn-container" *ngIf="!(http || dns)">
<button color="primary" mat-raised-button (click)="loadHttpToken()">HTTP</button>
<button color="primary" mat-raised-button (click)="loadDnsToken()">DNS</button>
</div>
</div>
<div *ngIf="http">
<p>HTTP TOKEN</p>
<p class="entry">{{http?.url}}.txt</p>
<div *ngIf="dns">
<p>DNS TOKEN</p>
<div class="line" *ngIf="dns?.token">
<p class="entry">{{dns?.token}}</p>
<button color="primary" [disabled]="copied == data.clientSecret" matTooltip="copy to clipboard"
appCopyToClipboard [valueToCopy]="dns.token" (copiedValue)="copied = $event" mat-icon-button>
<i *ngIf="copied != dns.token" class="las la-clipboard"></i>
<i *ngIf="copied == dns.token" class="las la-clipboard-check"></i>
</button>
<div class="btn-container">
<button mat-stroked-button (click)="saveFile()"
color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
</div>
</div>
<p class="entry">{{dns?.url}}</p>
</div>
<div *ngIf="dns">
<p>DNS TOKEN</p>
<div class="line" *ngIf="dns?.token">
<p class="entry">{{dns?.token}}</p>
<button color="primary" [disabled]="copied == data.clientSecret" matTooltip="copy to clipboard"
appCopyToClipboard [valueToCopy]="dns.token" (copiedValue)="copied = $event" mat-icon-button>
<i *ngIf="copied != dns.token" class="las la-clipboard"></i>
<i *ngIf="copied == dns.token" class="las la-clipboard-check"></i>
</button>
</div>
<p class="entry">{{dns?.url}}</p>
</div>
</ng-container>
</div>
<div mat-dialog-actions class="action">
<button mat-button class="ok-button" (click)="closeDialog()">

View File

@ -19,6 +19,8 @@ export class DomainVerificationComponent {
public dns!: OrgDomainValidationResponse.AsObject;
public copied: string = '';
public showNew: boolean = false;
constructor(
private toast: ToastService,
public dialogRef: MatDialogRef<DomainVerificationComponent>,
@ -26,6 +28,10 @@ export class DomainVerificationComponent {
private mgmtService: ManagementService,
) {
this.domain = data.domain;
console.log(data);
if (this.domain.validationType === OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_UNSPECIFIED) {
this.showNew = true;
}
}
async loadHttpToken(): Promise<void> {

View File

@ -21,7 +21,7 @@
color="warn" mat-icon-button (click)="removeDomain(domain.domain)"><i
class="las la-trash"></i></button>
</div>
<p class="new-desc">{{'ORG.PAGES.ORGDOMAIN_VERIFICATION' | translate}}</p>
<p class="new-desc">{{'ORG.PAGES.ORGDOMAIN.VERIFICATION' | translate}}</p>
<button [disabled]="(canwrite$ | async) == false" matTooltip="Add domain" mat-raised-button
color="primary" (click)="addNewDomain()">{{'ORG.DOMAINS.NEW' | translate}}
</button>

View File

@ -5,6 +5,4 @@ import { Component } from '@angular/core';
templateUrl: './owned-projects.component.html',
styleUrls: ['./owned-projects.component.scss'],
})
export class OwnedProjectsComponent {
constructor() { }
}
export class OwnedProjectsComponent { }

View File

@ -5,7 +5,8 @@ import { Org } from 'src/app/proto/generated/auth_pb';
import { StorageService } from '../storage.service';
const orgKey = 'x-zitadel-orgid';
const ORG_HEADER_KEY = 'x-zitadel-orgid';
const ORG_STORAGE_KEY = 'organization';
@Injectable({ providedIn: 'root' })
export class OrgInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
constructor(private readonly storageService: StorageService) { }
@ -13,14 +14,19 @@ export class OrgInterceptor<TReq = unknown, TResp = unknown> implements UnaryInt
public intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
const metadata = request.getMetadata();
const org: Org.AsObject | null = (this.storageService.getItem('organization'));
const org: Org.AsObject | null = (this.storageService.getItem(ORG_STORAGE_KEY));
if (org) {
metadata[orgKey] = `${org.id}`;
metadata[ORG_HEADER_KEY] = `${org.id}`;
}
return invoker(request).then((response: any) => {
return response;
}).catch((error: any) => {
if (error.code === 7 && error.message.startsWith('Organisation doesn\'t exist')) {
this.storageService.removeItem(ORG_STORAGE_KEY);
}
return Promise.reject(error);
});
}
}

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { OAuthStorage } from 'angular-oauth2-oidc';
const STORAGE_PREFIX = 'zitadel';
@Injectable({
providedIn: 'root',
})
export class StorageService implements OAuthStorage {
private storage: Storage = window.sessionStorage;
@ -28,7 +28,7 @@ export class StorageService implements OAuthStorage {
}
public getPrefixedKey(key: string): string {
return `caos:${key}`;
return `${STORAGE_PREFIX}:${key}`;
}
}

View File

@ -376,14 +376,22 @@
"ACTIVE":"Aktiv",
"CREATE":"Organisation erstellen",
"ORGDETAIL_TITLE":"Gebe den Namen und die Domain für die neue Organisation ein.",
"ORGDOMAIN_TITLE":"Verifikation der Domain der Organisation",
"ORGDOMAIN_VERIFICATION":"Überprüfe den Besitz Deiner Domain, indem Du eine Bestätigungsdatei herunterlädst und unter der angegebenen URL speicherst, oder indem Du sie mit einem DNS-Eintrag verifizierst.",
"ORGDOMAIN_VERIFICATION_SKIP":"Du kannst die Überprüfung vorerst überspringen und Deine Organisation erstellen. Um Deine Organisation jedoch verwenden zu können, muss dieser Schritt abgeschlossen sein.",
"ORGDETAILUSER_TITLE":"Organisationsbesitzer hinzufügen",
"ORGDOMAIN_VERIFICATION_VALIDATION_DESC":"Die Tokens werden regelmässig überprüft, um sicherzustellen, dass Du weiterhin im Besitz der Domain bist.",
"ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE":"Neues Token anfordern",
"ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC":"Wenn Du ein neues Token anfordern willst, klicke auf die gewünschte Methode. Wenn Du ein vorhandenes Token validieren möchtest, klicke auf \"Validieren\".",
"ORGDOMAIN_VERIFICATION_VALIDATION_ONGOING":"Ein Token zur Validierung wurde bereits angefragt. Klicke auf \"Validieren\", um dieses Token zu validieren.",
"ORGDOMAIN": {
"TITLE":"Verifikation der Domain der Organisation",
"VERIFICATION":"Überprüfe den Besitz Deiner Domain, indem Du eine Bestätigungsdatei herunterlädst und unter der angegebenen URL speicherst, oder indem Du sie mit einem DNS-Eintrag verifizierst.",
"VERIFICATION_SKIP":"Du kannst die Überprüfung vorerst überspringen und Deine Organisation erstellen. Um Deine Organisation jedoch verwenden zu können, muss dieser Schritt abgeschlossen sein.",
"VERIFICATION_VALIDATION_DESC":"Die Tokens werden regelmässig überprüft, um sicherzustellen, dass Du weiterhin im Besitz der Domain bist.",
"VERIFICATION_NEWTOKEN_TITLE":"Neues Token anfordern",
"VERIFICATION_NEWTOKEN_DESC":"Wenn Du ein neues Token anfordern willst, klicke auf die gewünschte Methode. Wenn Du ein vorhandenes Token validieren möchtest, klicke auf \"Validieren\".",
"VERIFICATION_VALIDATION_ONGOING":"Ein Token zur Validierung wurde bereits angefragt. Klicke auf \"Validieren\", um dieses Token zu validieren.",
"VERIFICATION_VALIDATION_ONGOING_TYPE":"Typ des Tokens:",
"REQUESTNEWTOKEN":"Neues Token anfordern",
"TYPES": {
"1":"HTTP",
"2":"DNS"
}
},
"DOWNLOAD_FILE":"Datei herunterladen",
"SELECTORGTOOLTIP":"Diese Organisation auswählen",
"PRIMARYDOMAIN":"Primäre Domain",

View File

@ -376,14 +376,22 @@
"ACTIVE":"Active",
"CREATE":"Create Organisation",
"ORGDETAIL_TITLE":"Enter the name and domain of your new organisation.",
"ORGDOMAIN_TITLE":"Organisation Domain Ownership Verification",
"ORGDOMAIN_VERIFICATION":"Verify the ownership of your domain. You need to download a verification file and upload it at the provided URL listed below, or place a TXT Record DNS entry for the provided URL. To complete, click the button to verify.",
"ORGDOMAIN_VERIFICATION_SKIP":"You can skip verification for now and continue to create your organisation, but in order to use your organisation this step has to be completed!",
"ORGDETAILUSER_TITLE":"Configure Organisation Owner",
"ORGDOMAIN_VERIFICATION_VALIDATION_DESC":"The tokens are checked regularly to ensure you are still owner of the domain.",
"ORGDOMAIN_VERIFICATION_NEWTOKEN_TITLE":"Request New Token",
"ORGDOMAIN_VERIFICATION_NEWTOKEN_DESC":"If you want to request a new token, select you preferred method. If you want to validate a persisting token, click the button above.",
"ORGDOMAIN_VERIFICATION_VALIDATION_ONGOING":"A verification token has already been requested. Click on the button to trigger a verification check.",
"ORGDOMAIN": {
"TITLE":"Organisation Domain Ownership Verification",
"VERIFICATION":"Verify the ownership of your domain. You need to download a verification file and upload it at the provided URL listed below, or place a TXT Record DNS entry for the provided URL. To complete, click the button to verify.",
"VERIFICATION_SKIP":"You can skip verification for now and continue to create your organisation, but in order to use your organisation this step has to be completed!",
"VERIFICATION_VALIDATION_DESC":"The tokens are checked regularly to ensure you are still owner of the domain.",
"VERIFICATION_NEWTOKEN_TITLE":"Request New Token",
"VERIFICATION_NEWTOKEN_DESC":"If you want to request a new token, select you preferred method. If you want to validate a persisting token, click the button above.",
"VERIFICATION_VALIDATION_ONGOING":"A verification token has already been requested. Click on the button to trigger a verification check.",
"VERIFICATION_VALIDATION_ONGOING_TYPE":"Type of the token:",
"REQUESTNEWTOKEN":"Request new Token",
"TYPES": {
"1":"HTTP",
"2":"DNS"
}
},
"DOWNLOAD_FILE":"Download File",
"SELECTORGTOOLTIP":"Select this organisation.",
"PRIMARYDOMAIN":"Primary Domain",

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

View File

@ -23,7 +23,6 @@
<meta property="og:description" content="Console Management Platform for ZITADEL IAM" />
<meta property="description" content="Management Platform for ZITADEL IAM" />
<meta property="og:image" content="https://www.zitadel.ch/zitadel-social-preview25.png" />
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@zitadel_ch">
<meta name="twitter:title" content="ZITADEL Console" />