mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-27 04:35:16 +01:00
Add generate cli secret in user profile page
add cli secret button in user profile page, OIDC users can click this button to regenerate a cli secret, if the user does so, then the past cli secret will be abandoned. Signed-off-by: Yogi_Wang <yawang@vmware.com>
This commit is contained in:
parent
d53f21bf3c
commit
f164738246
@ -0,0 +1,12 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AccountSettingsModalService } from './account-settings-modal-service.service';
|
||||||
|
|
||||||
|
describe('AccountSettingsModalServiceService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: AccountSettingsModalService = TestBed.get(AccountSettingsModalService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Http } from '@angular/http';
|
||||||
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import { throwError as observableThrowError, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AccountSettingsModalService {
|
||||||
|
|
||||||
|
constructor(private http: Http) { }
|
||||||
|
generateCli(userId): Observable<any> {
|
||||||
|
return this.http.post(`/api/users/${userId}/gen_cli_secret`, {}).pipe( map(response => response)
|
||||||
|
, catchError(error => observableThrowError(error)));
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group form-group-override" *ngIf="account.oidc_user_meta">
|
<div class="form-group form-group-override cli-secret" *ngIf="account.oidc_user_meta">
|
||||||
<label for="cli_password" aria-haspopup="true" class="form-group-label-override"><span class="label-inner-text">{{'PROFILE.CLI_PASSWORD' | translate}}</span>
|
<label for="cli_password" aria-haspopup="true" class="form-group-label-override"><span class="label-inner-text">{{'PROFILE.CLI_PASSWORD' | translate}}</span>
|
||||||
<clr-tooltip>
|
<clr-tooltip>
|
||||||
<clr-icon clrTooltipTrigger shape="info-circle" size="20"></clr-icon>
|
<clr-icon clrTooltipTrigger shape="info-circle" size="20"></clr-icon>
|
||||||
@ -60,9 +60,13 @@
|
|||||||
</clr-tooltip-content>
|
</clr-tooltip-content>
|
||||||
</clr-tooltip></label>
|
</clr-tooltip></label>
|
||||||
<input type="password" name="cli_password" disabled [ngModel]="'account.oidc_user_meta.secret'" size="33">
|
<input type="password" name="cli_password" disabled [ngModel]="'account.oidc_user_meta.secret'" size="33">
|
||||||
<div class="rename-tool">
|
<button (click)="generateCli(account.user_id)" class="btn btn-outline btn-sm btn-padding-less" *ngIf="showGenerateCli">
|
||||||
<hbr-copy-input #copyInput (onCopySuccess)="onSuccess($event)" (onCopyError)="onCpError($event)" iconMode="true" defaultValue="{{account.oidc_user_meta.secret}}"></hbr-copy-input>
|
{{'PROFILE.ADMIN_CIL_SECRET_BUTTON' | translate}}
|
||||||
|
</button>
|
||||||
|
<div class="rename-tool reset-cli">
|
||||||
|
<hbr-copy-input #copyInput (onCopySuccess)="onSuccess($event)" (onCopyError)="onError($event)" iconMode="true" [defaultValue]="account.oidc_user_meta.secret"></hbr-copy-input>
|
||||||
</div>
|
</div>
|
||||||
|
<div (click)="showGenerateCliFn()" *ngIf="!showGenerateCli" class="hidden-generate-cli">···</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
@ -72,4 +76,5 @@
|
|||||||
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
|
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate}}</button>
|
||||||
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="submit()">{{'BUTTON.OK' | translate}}</button>
|
<button type="button" class="btn btn-primary" [disabled]="!isValid || showProgress" (click)="submit()">{{'BUTTON.OK' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
||||||
|
<confirmation-dialog #confirmationDialog (confirmAction)="confirmGenerate($event)"></confirmation-dialog>
|
||||||
|
@ -14,4 +14,21 @@ clr-modal {
|
|||||||
.label-inner-text{
|
.label-inner-text{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.cli-secret {
|
||||||
|
align-items: center;
|
||||||
|
.reset-cli {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.btn-padding-less {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hidden-generate-cli {
|
||||||
|
font-size: 30px;
|
||||||
|
color: grey;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
}
|
}
|
@ -15,6 +15,7 @@ import { ChangeDetectorRef } from '@angular/core';
|
|||||||
import { Component, OnInit, ViewChild, AfterViewChecked } from "@angular/core";
|
import { Component, OnInit, ViewChild, AfterViewChecked } from "@angular/core";
|
||||||
import { NgForm } from "@angular/forms";
|
import { NgForm } from "@angular/forms";
|
||||||
import { Router, NavigationExtras } from "@angular/router";
|
import { Router, NavigationExtras } from "@angular/router";
|
||||||
|
import { ConfirmationMessage } from '../../shared/confirmation-dialog/confirmation-message';
|
||||||
|
|
||||||
import { SessionUser } from "../../shared/session-user";
|
import { SessionUser } from "../../shared/session-user";
|
||||||
import { SessionService } from "../../shared/session.service";
|
import { SessionService } from "../../shared/session.service";
|
||||||
@ -23,6 +24,12 @@ import { MessageHandlerService } from "../../shared/message-handler/message-hand
|
|||||||
import { SearchTriggerService } from "../../base/global-search/search-trigger.service";
|
import { SearchTriggerService } from "../../base/global-search/search-trigger.service";
|
||||||
import { CommonRoutes } from "../../shared/shared.const";
|
import { CommonRoutes } from "../../shared/shared.const";
|
||||||
import { CopyInputComponent } from "@harbor/ui";
|
import { CopyInputComponent } from "@harbor/ui";
|
||||||
|
import { AccountSettingsModalService } from './account-settings-modal-service.service';
|
||||||
|
import { ConfirmationDialogComponent } from "../../shared/confirmation-dialog/confirmation-dialog.component";
|
||||||
|
import {
|
||||||
|
ConfirmationTargets,
|
||||||
|
ConfirmationButtons
|
||||||
|
} from "../../shared/shared.const";
|
||||||
@Component({
|
@Component({
|
||||||
selector: "account-settings-modal",
|
selector: "account-settings-modal",
|
||||||
templateUrl: "account-settings-modal.component.html",
|
templateUrl: "account-settings-modal.component.html",
|
||||||
@ -44,6 +51,9 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
|||||||
newAdminName = "admin@harbor.local";
|
newAdminName = "admin@harbor.local";
|
||||||
renameConfirmation = false;
|
renameConfirmation = false;
|
||||||
// confirmRename = false;
|
// confirmRename = false;
|
||||||
|
showGenerateCli: boolean = false;
|
||||||
|
@ViewChild("confirmationDialog")
|
||||||
|
confirmationDialogComponent: ConfirmationDialogComponent;
|
||||||
|
|
||||||
accountFormRef: NgForm;
|
accountFormRef: NgForm;
|
||||||
@ViewChild("accountSettingsFrom") accountForm: NgForm;
|
@ViewChild("accountSettingsFrom") accountForm: NgForm;
|
||||||
@ -55,6 +65,7 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
|||||||
private msgHandler: MessageHandlerService,
|
private msgHandler: MessageHandlerService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private searchTrigger: SearchTriggerService,
|
private searchTrigger: SearchTriggerService,
|
||||||
|
private accountSettingsService: AccountSettingsModalService,
|
||||||
private ref: ChangeDetectorRef
|
private ref: ChangeDetectorRef
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -236,7 +247,7 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
|||||||
account_settings_email: true,
|
account_settings_email: true,
|
||||||
account_settings_full_name: true
|
account_settings_full_name: true
|
||||||
};
|
};
|
||||||
|
this.showGenerateCli = false;
|
||||||
this.opened = true;
|
this.opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,4 +338,27 @@ export class AccountSettingsModalComponent implements OnInit, AfterViewChecked {
|
|||||||
onError(event) {
|
onError(event) {
|
||||||
this.inlineAlert.showInlineError({message: 'PROFILE.COPY_ERROR'});
|
this.inlineAlert.showInlineError({message: 'PROFILE.COPY_ERROR'});
|
||||||
}
|
}
|
||||||
|
generateCli(userId): void {
|
||||||
|
let generateCliMessage = new ConfirmationMessage(
|
||||||
|
'PROFILE.CONFIRM_TITLE_CLI_GENERATE',
|
||||||
|
'PROFILE.CONFIRM_BODY_CLI_GENERATE',
|
||||||
|
'',
|
||||||
|
userId,
|
||||||
|
ConfirmationTargets.TARGET,
|
||||||
|
ConfirmationButtons.CONFIRM_CANCEL);
|
||||||
|
this.confirmationDialogComponent.open(generateCliMessage);
|
||||||
|
}
|
||||||
|
showGenerateCliFn() {
|
||||||
|
this.showGenerateCli = !this.showGenerateCli;
|
||||||
|
}
|
||||||
|
confirmGenerate(confirmData): void {
|
||||||
|
let userId = confirmData.data;
|
||||||
|
this.accountSettingsService.generateCli(userId).subscribe(cliSecret => {
|
||||||
|
let secret = JSON.parse(cliSecret._body).secret;
|
||||||
|
this.account.oidc_user_meta.secret = secret;
|
||||||
|
this.inlineAlert.showInlineSuccess({message: 'PROFILE.GENERATE_SUCCESS'});
|
||||||
|
}, error => {
|
||||||
|
this.inlineAlert.showInlineError({message: 'PROFILE.GENERATE_ERROR'});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import { ForgotPasswordComponent } from './password-setting/forgot-password/forg
|
|||||||
import { ResetPasswordComponent } from './password-setting/reset-password/reset-password.component';
|
import { ResetPasswordComponent } from './password-setting/reset-password/reset-password.component';
|
||||||
import { SignUpPageComponent } from './sign-up/sign-up-page.component';
|
import { SignUpPageComponent } from './sign-up/sign-up-page.component';
|
||||||
import { PasswordSettingService } from './password-setting/password-setting.service';
|
import { PasswordSettingService } from './password-setting/password-setting.service';
|
||||||
|
import { AccountSettingsModalService } from './account-settings/account-settings-modal-service.service';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -49,6 +50,6 @@ import { PasswordSettingService } from './password-setting/password-setting.serv
|
|||||||
SignUpComponent,
|
SignUpComponent,
|
||||||
SignUpPageComponent],
|
SignUpPageComponent],
|
||||||
|
|
||||||
providers: [PasswordSettingService]
|
providers: [PasswordSettingService, AccountSettingsModalService]
|
||||||
})
|
})
|
||||||
export class AccountModule { }
|
export class AccountModule { }
|
||||||
|
@ -106,7 +106,12 @@
|
|||||||
"CLI_PASSWORD": "CLI secret",
|
"CLI_PASSWORD": "CLI secret",
|
||||||
"CLI_PASSWORD_TIP": "You can use this cli secret as password when using docker/helm cli to access Harbor.",
|
"CLI_PASSWORD_TIP": "You can use this cli secret as password when using docker/helm cli to access Harbor.",
|
||||||
"COPY_SUCCESS": "copy success",
|
"COPY_SUCCESS": "copy success",
|
||||||
"COPY_ERROR": "copy failed"
|
"COPY_ERROR": "copy failed",
|
||||||
|
"ADMIN_CIL_SECRET_BUTTON": "GENERATE SECRET",
|
||||||
|
"GENERATE_SUCCESS": "generate CLI secret success",
|
||||||
|
"GENERATE_ERROR": "generate CLI secret failed",
|
||||||
|
"CONFIRM_TITLE_CLI_GENERATE": "Are you sure you can regenerate secret?",
|
||||||
|
"CONFIRM_BODY_CLI_GENERATE": "If you regenerate cli secret, the old cli secret will be discarded"
|
||||||
},
|
},
|
||||||
"CHANGE_PWD": {
|
"CHANGE_PWD": {
|
||||||
"TITLE": "Change Password",
|
"TITLE": "Change Password",
|
||||||
|
@ -106,7 +106,12 @@
|
|||||||
"CLI_PASSWORD": "CLI secreto",
|
"CLI_PASSWORD": "CLI secreto",
|
||||||
"CLI_PASSWORD_TIP": "Puede utilizar este generador CLI secreto como utilizando Docker / Helm CLI para acceder a puerto.",
|
"CLI_PASSWORD_TIP": "Puede utilizar este generador CLI secreto como utilizando Docker / Helm CLI para acceder a puerto.",
|
||||||
"COPY_SUCCESS": "Copiar el éxito",
|
"COPY_SUCCESS": "Copiar el éxito",
|
||||||
"COPY_ERROR": "Copia no"
|
"COPY_ERROR": "Copia no",
|
||||||
|
"ADMIN_CIL_SECRET_BUTTON": "GENERATE SECRET",
|
||||||
|
"GENERATE_SUCCESS": "generate CLI secret success",
|
||||||
|
"GENERATE_ERROR": "generate CLI secret failed",
|
||||||
|
"CONFIRM_TITLE_CLI_GENERATE": "Are you sure you can regenerate secret?",
|
||||||
|
"CONFIRM_BODY_CLI_GENERATE": "If you regenerate cli secret, the old cli secret will be discarded"
|
||||||
},
|
},
|
||||||
"CHANGE_PWD": {
|
"CHANGE_PWD": {
|
||||||
"TITLE": "Cambiar contraseña",
|
"TITLE": "Cambiar contraseña",
|
||||||
|
@ -93,7 +93,12 @@
|
|||||||
"CLI_PASSWORD": "CLI secret",
|
"CLI_PASSWORD": "CLI secret",
|
||||||
"CLI_PASSWORD_TIP": "vous pouvez utiliser ce cli secret comme mot de passe quand utiliser docker / barre l'accès à harbor.",
|
"CLI_PASSWORD_TIP": "vous pouvez utiliser ce cli secret comme mot de passe quand utiliser docker / barre l'accès à harbor.",
|
||||||
"COPY_SUCCESS": "copie de succès",
|
"COPY_SUCCESS": "copie de succès",
|
||||||
"COPY_ERROR": "copie a échoué"
|
"COPY_ERROR": "copie a échoué",
|
||||||
|
"ADMIN_CIL_SECRET_BUTTON": "GENERATE SECRET",
|
||||||
|
"GENERATE_SUCCESS": "generate CLI secret success",
|
||||||
|
"GENERATE_ERROR": "generate CLI secret failed",
|
||||||
|
"CONFIRM_TITLE_CLI_GENERATE": "Are you sure you can regenerate secret?",
|
||||||
|
"CONFIRM_BODY_CLI_GENERATE": "If you regenerate cli secret, the old cli secret will be discarded"
|
||||||
},
|
},
|
||||||
"CHANGE_PWD": {
|
"CHANGE_PWD": {
|
||||||
"TITLE": "Modifier le mot de passe",
|
"TITLE": "Modifier le mot de passe",
|
||||||
|
@ -104,7 +104,12 @@
|
|||||||
"CLI_PASSWORD": "Segredo CLI",
|
"CLI_PASSWORD": "Segredo CLI",
|
||||||
"CLI_PASSWORD_TIP": "Você Pode USAR este Segredo de clitóris Como senha Ao USAR clitóris de estivador /leme para acessar Harbor.",
|
"CLI_PASSWORD_TIP": "Você Pode USAR este Segredo de clitóris Como senha Ao USAR clitóris de estivador /leme para acessar Harbor.",
|
||||||
"COPY_SUCCESS": "SUCESSO de cópia",
|
"COPY_SUCCESS": "SUCESSO de cópia",
|
||||||
"COPY_ERROR": "Cópia falhou"
|
"COPY_ERROR": "Cópia falhou",
|
||||||
|
"ADMIN_CIL_SECRET_BUTTON": "GENERATE SECRET",
|
||||||
|
"GENERATE_SUCCESS": "generate CLI secret success",
|
||||||
|
"GENERATE_ERROR": "generate CLI secret failed",
|
||||||
|
"CONFIRM_TITLE_CLI_GENERATE": "Are you sure you can regenerate secret?",
|
||||||
|
"CONFIRM_BODY_CLI_GENERATE": "If you regenerate cli secret, the old cli secret will be discarded"
|
||||||
},
|
},
|
||||||
"CHANGE_PWD": {
|
"CHANGE_PWD": {
|
||||||
"TITLE": "Alterar Senha",
|
"TITLE": "Alterar Senha",
|
||||||
|
@ -105,7 +105,12 @@
|
|||||||
"CLI_PASSWORD": "CLI密码",
|
"CLI_PASSWORD": "CLI密码",
|
||||||
"CLI_PASSWORD_TIP": "使用docker/helm cli访问Harbor时,可以使用此cli密码作为密码。",
|
"CLI_PASSWORD_TIP": "使用docker/helm cli访问Harbor时,可以使用此cli密码作为密码。",
|
||||||
"COPY_SUCCESS": "复制成功",
|
"COPY_SUCCESS": "复制成功",
|
||||||
"COPY_ERROR": "复制失败"
|
"COPY_ERROR": "复制失败",
|
||||||
|
"ADMIN_CIL_SECRET_BUTTON": "生成新的CLI密码",
|
||||||
|
"GENERATE_SUCCESS": "成功生成新的CLI密码",
|
||||||
|
"GENERATE_ERROR": "生成新的CLI密码失败",
|
||||||
|
"CONFIRM_TITLE_CLI_GENERATE": "您确定需要重新生成cli secret吗?",
|
||||||
|
"CONFIRM_BODY_CLI_GENERATE": "如果您重新生成cli secret,那么旧的cli secret将会被弃用"
|
||||||
},
|
},
|
||||||
"CHANGE_PWD": {
|
"CHANGE_PWD": {
|
||||||
"TITLE": "修改密码",
|
"TITLE": "修改密码",
|
||||||
|
Loading…
Reference in New Issue
Block a user