mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-03 13:33:32 +01:00
[PM-14990] Add password prompt for ssh key import (#12105)
* Add password prompt for ssh key import * Remove empty line * Convert to switch statement
This commit is contained in:
parent
2767851925
commit
f79141c421
@ -207,6 +207,21 @@
|
||||
"sshKeyGenerated": {
|
||||
"message": "A new SSH key was generated"
|
||||
},
|
||||
"sshKeyWrongPassword": {
|
||||
"message": "The password you entered is incorrect."
|
||||
},
|
||||
"importSshKey": {
|
||||
"message": "Import"
|
||||
},
|
||||
"confirmSshKeyPassword": {
|
||||
"message": "Confirm password"
|
||||
},
|
||||
"enterSshKeyPasswordDesc": {
|
||||
"message": "Enter the password for the SSH key."
|
||||
},
|
||||
"enterSshKeyPassword": {
|
||||
"message": "Enter password"
|
||||
},
|
||||
"sshAgentUnlockRequired": {
|
||||
"message": "Please unlock your vault to approve the SSH key request."
|
||||
},
|
||||
@ -1752,10 +1767,10 @@
|
||||
"deleteAccountWarning": {
|
||||
"message": "Deleting your account is permanent. It cannot be undone."
|
||||
},
|
||||
"cannotDeleteAccount":{
|
||||
"cannotDeleteAccount": {
|
||||
"message": "Cannot delete account"
|
||||
},
|
||||
"cannotDeleteAccountDesc":{
|
||||
"cannotDeleteAccountDesc": {
|
||||
"message": "This action cannot be completed because your account is owned by an organization. Contact your organization administrator for additional details."
|
||||
},
|
||||
"accountDeleted": {
|
||||
|
@ -2,6 +2,7 @@ import { DatePipe } from "@angular/common";
|
||||
import { Component, NgZone, OnChanges, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { NgForm } from "@angular/forms";
|
||||
import { sshagent as sshAgent } from "desktop_native/napi";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
@ -22,6 +23,7 @@ import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folde
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { SshKeyPasswordPromptComponent } from "@bitwarden/importer/ui";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
const BroadcasterSubscriptionId = "AddEditComponent";
|
||||
@ -170,42 +172,64 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
|
||||
}
|
||||
}
|
||||
|
||||
async importSshKeyFromClipboard() {
|
||||
async importSshKeyFromClipboard(password: string = "") {
|
||||
const key = await this.platformUtilsService.readFromClipboard();
|
||||
const parsedKey = await ipc.platform.sshAgent.importKey(key, "");
|
||||
if (parsedKey == null || parsedKey.status === sshAgent.SshKeyImportStatus.ParsingError) {
|
||||
const parsedKey = await ipc.platform.sshAgent.importKey(key, password);
|
||||
if (parsedKey == null) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("invalidSshKey"),
|
||||
});
|
||||
return;
|
||||
} else if (parsedKey.status === sshAgent.SshKeyImportStatus.UnsupportedKeyType) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyTypeUnsupported"),
|
||||
});
|
||||
} else if (
|
||||
parsedKey.status === sshAgent.SshKeyImportStatus.PasswordRequired ||
|
||||
parsedKey.status === sshAgent.SshKeyImportStatus.WrongPassword
|
||||
) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyPasswordUnsupported"),
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
this.cipher.sshKey.privateKey = parsedKey.sshKey.privateKey;
|
||||
this.cipher.sshKey.publicKey = parsedKey.sshKey.publicKey;
|
||||
this.cipher.sshKey.keyFingerprint = parsedKey.sshKey.keyFingerprint;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyPasted"),
|
||||
});
|
||||
}
|
||||
|
||||
switch (parsedKey.status) {
|
||||
case sshAgent.SshKeyImportStatus.ParsingError:
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("invalidSshKey"),
|
||||
});
|
||||
return;
|
||||
case sshAgent.SshKeyImportStatus.UnsupportedKeyType:
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyTypeUnsupported"),
|
||||
});
|
||||
return;
|
||||
case sshAgent.SshKeyImportStatus.PasswordRequired:
|
||||
case sshAgent.SshKeyImportStatus.WrongPassword:
|
||||
if (password !== "") {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyWrongPassword"),
|
||||
});
|
||||
} else {
|
||||
password = await this.getSshKeyPassword();
|
||||
await this.importSshKeyFromClipboard(password);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
this.cipher.sshKey.privateKey = parsedKey.sshKey.privateKey;
|
||||
this.cipher.sshKey.publicKey = parsedKey.sshKey.publicKey;
|
||||
this.cipher.sshKey.keyFingerprint = parsedKey.sshKey.keyFingerprint;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: "",
|
||||
message: this.i18nService.t("sshKeyPasted"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getSshKeyPassword(): Promise<string> {
|
||||
const dialog = this.dialogService.open<string>(SshKeyPasswordPromptComponent, {
|
||||
ariaModal: true,
|
||||
});
|
||||
|
||||
return await lastValueFrom(dialog.closed);
|
||||
}
|
||||
|
||||
async typeChange() {
|
||||
|
@ -1,3 +1,4 @@
|
||||
export * from "./import-error-dialog.component";
|
||||
export * from "./import-success-dialog.component";
|
||||
export * from "./file-password-prompt.component";
|
||||
export * from "./sshkey-password-prompt.component";
|
||||
|
@ -0,0 +1,31 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog>
|
||||
<span bitDialogTitle>
|
||||
{{ "enterSshKeyPassword" | i18n }}
|
||||
</span>
|
||||
|
||||
<div bitDialogContent>
|
||||
{{ "enterSshKeyPasswordDesc" | i18n }}
|
||||
<bit-form-field class="tw-mt-6">
|
||||
<bit-label>{{ "confirmSshKeyPassword" | i18n }}</bit-label>
|
||||
<input
|
||||
bitInput
|
||||
type="password"
|
||||
formControlName="sshKeyPassword"
|
||||
appAutofocus
|
||||
appInputVerbatim
|
||||
/>
|
||||
<button type="button" bitSuffix bitIconButton bitPasswordInputToggle></button>
|
||||
</bit-form-field>
|
||||
</div>
|
||||
|
||||
<ng-container bitDialogFooter>
|
||||
<button bitButton buttonType="primary" type="submit">
|
||||
<span>{{ "importSshKey" | i18n }}</span>
|
||||
</button>
|
||||
<button bitButton bitDialogClose buttonType="secondary" type="button">
|
||||
<span>{{ "cancel" | i18n }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
</form>
|
@ -0,0 +1,46 @@
|
||||
import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
FormFieldModule,
|
||||
IconButtonModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
templateUrl: "sshkey-password-prompt.component.html",
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
DialogModule,
|
||||
FormFieldModule,
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
IconButtonModule,
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
})
|
||||
export class SshKeyPasswordPromptComponent {
|
||||
protected formGroup = this.formBuilder.group({
|
||||
sshKeyPassword: ["", Validators.required],
|
||||
});
|
||||
|
||||
constructor(
|
||||
public dialogRef: DialogRef,
|
||||
protected formBuilder: FormBuilder,
|
||||
) {}
|
||||
|
||||
submit = () => {
|
||||
this.formGroup.markAsTouched();
|
||||
if (!this.formGroup.valid) {
|
||||
return;
|
||||
}
|
||||
this.dialogRef.close(this.formGroup.value.sshKeyPassword);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user