mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
update enc key
This commit is contained in:
@@ -92,6 +92,7 @@ import { TwoFactorSetupComponent } from './settings/two-factor-setup.component';
|
||||
import { TwoFactorU2fComponent } from './settings/two-factor-u2f.component';
|
||||
import { TwoFactorVerifyComponent } from './settings/two-factor-verify.component';
|
||||
import { TwoFactorYubiKeyComponent } from './settings/two-factor-yubikey.component';
|
||||
import { UpdateKeyComponent } from './settings/update-key.component';
|
||||
import { UpdateLicenseComponent } from './settings/update-license.component';
|
||||
import { UserBillingComponent } from './settings/user-billing.component';
|
||||
import { VerifyEmailComponent } from './settings/verify-email.component';
|
||||
@@ -241,6 +242,7 @@ import { SearchPipe } from 'jslib/angular/pipes/search.pipe';
|
||||
TwoFactorU2fComponent,
|
||||
TwoFactorVerifyComponent,
|
||||
TwoFactorYubiKeyComponent,
|
||||
UpdateKeyComponent,
|
||||
UpdateLicenseComponent,
|
||||
UserBillingComponent,
|
||||
UserLayoutComponent,
|
||||
@@ -280,6 +282,7 @@ import { SearchPipe } from 'jslib/angular/pipes/search.pipe';
|
||||
TwoFactorRecoveryComponent,
|
||||
TwoFactorU2fComponent,
|
||||
TwoFactorYubiKeyComponent,
|
||||
UpdateKeyComponent,
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent],
|
||||
|
||||
28
src/app/settings/update-key.component.html
Normal file
28
src/app/settings/update-key.component.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">{{'updateEncryptionKey' | i18n}}</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" attr.aria-label="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{'updateEncryptionKeyShortDesc' | i18n}} {{'updateEncryptionKeyDesc' | i18n}}
|
||||
<a href="https://help.bitwarden.com/article/update-encryption-key/" target="_blank" rel="noopener">{{'learnMore' | i18n}}</a>
|
||||
</p>
|
||||
<app-callout type="warning">{{'updateEncryptionKeyWarning' | i18n}}</app-callout>
|
||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
||||
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control" [(ngModel)]="masterPassword" required
|
||||
appAutofocus appInputVerbatim>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button appBlurClick type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<span>{{'updateEncryptionKey' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
98
src/app/settings/update-key.component.ts
Normal file
98
src/app/settings/update-key.component.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import {
|
||||
Toast,
|
||||
ToasterService,
|
||||
} from 'angular2-toaster';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
|
||||
import { CipherString } from 'jslib/models/domain/cipherString';
|
||||
|
||||
import { CipherWithIdRequest } from 'jslib/models/request/cipherWithIdRequest';
|
||||
import { FolderWithIdRequest } from 'jslib/models/request/folderWithIdRequest';
|
||||
import { UpdateKeyRequest } from 'jslib/models/request/updateKeyRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-update-key',
|
||||
templateUrl: 'update-key.component.html',
|
||||
})
|
||||
export class UpdateKeyComponent {
|
||||
masterPassword: string;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||
private analytics: Angulartics2, private toasterService: ToasterService,
|
||||
private cryptoService: CryptoService, private messagingService: MessagingService,
|
||||
private syncService: SyncService, private folderService: FolderService,
|
||||
private cipherService: CipherService) { }
|
||||
|
||||
async submit() {
|
||||
const hasEncKey = await this.cryptoService.hasEncKey();
|
||||
if (hasEncKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.masterPassword == null || this.masterPassword === '') {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPassRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.formPromise = this.makeRequest().then((request) => {
|
||||
return this.apiService.postAccountKey(request);
|
||||
});
|
||||
await this.formPromise;
|
||||
this.analytics.eventTrack.next({ action: 'Key Updated' });
|
||||
const toast: Toast = {
|
||||
type: 'success',
|
||||
title: this.i18nService.t('keyUpdated'),
|
||||
body: this.i18nService.t('logBackInOthersToo'),
|
||||
timeout: 15000,
|
||||
};
|
||||
this.toasterService.popAsync(toast);
|
||||
this.messagingService.send('logout');
|
||||
} catch { }
|
||||
}
|
||||
|
||||
private async makeRequest(): Promise<UpdateKeyRequest> {
|
||||
const key = await this.cryptoService.getKey();
|
||||
const encKey = await this.cryptoService.makeEncKey(key);
|
||||
const privateKey = await this.cryptoService.getPrivateKey();
|
||||
let encPrivateKey: CipherString = null;
|
||||
if (privateKey != null) {
|
||||
encPrivateKey = await this.cryptoService.encrypt(privateKey, encKey[0]);
|
||||
}
|
||||
const request = new UpdateKeyRequest();
|
||||
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
|
||||
request.key = encKey[1].encryptedString;
|
||||
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
|
||||
|
||||
await this.syncService.fullSync(true);
|
||||
|
||||
const folders = await this.folderService.getAllDecrypted();
|
||||
for (let i = 0; i < folders.length; i++) {
|
||||
const folder = await this.folderService.encrypt(folders[i], encKey[0]);
|
||||
request.folders.push(new FolderWithIdRequest(folder));
|
||||
}
|
||||
|
||||
const ciphers = await this.cipherService.getAllDecrypted();
|
||||
for (let i = 0; i < ciphers.length; i++) {
|
||||
if (ciphers[i].organizationId != null) {
|
||||
continue;
|
||||
}
|
||||
const cipher = await this.cipherService.encrypt(ciphers[i], encKey[0]);
|
||||
request.ciphers.push(new CipherWithIdRequest(cipher));
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,17 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card border-warning mb-4" *ngIf="showUpdateKey">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<i class="fa fa-warning fa-fw"></i> {{'updateKeyTitle' | i18n}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{'updateEncryptionKeyShortDesc' | i18n}}</p>
|
||||
<button class="btn btn-block btn-outline-secondary" type="button" (click)="updateKey()">
|
||||
{{'updateEncryptionKey' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{{'organizations' | i18n}}
|
||||
@@ -80,3 +91,4 @@
|
||||
<ng-template #bulkDeleteTemplate></ng-template>
|
||||
<ng-template #bulkMoveTemplate></ng-template>
|
||||
<ng-template #bulkShareTemplate></ng-template>
|
||||
<ng-template #updateKeyTemplate></ng-template>
|
||||
|
||||
@@ -18,6 +18,7 @@ import { CipherView } from 'jslib/models/view/cipherView';
|
||||
import { ModalComponent } from '../modal.component';
|
||||
|
||||
import { OrganizationsComponent } from '../settings/organizations.component';
|
||||
import { UpdateKeyComponent } from '../settings/update-key.component';
|
||||
import { AddEditComponent } from './add-edit.component';
|
||||
import { AttachmentsComponent } from './attachments.component';
|
||||
import { BulkDeleteComponent } from './bulk-delete.component';
|
||||
@@ -50,6 +51,7 @@ export class VaultComponent implements OnInit {
|
||||
@ViewChild('bulkDeleteTemplate', { read: ViewContainerRef }) bulkDeleteModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkMoveTemplate', { read: ViewContainerRef }) bulkMoveModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkShareTemplate', { read: ViewContainerRef }) bulkShareModalRef: ViewContainerRef;
|
||||
@ViewChild('updateKeyTemplate', { read: ViewContainerRef }) updateKeyModalRef: ViewContainerRef;
|
||||
|
||||
favorites: boolean = false;
|
||||
type: CipherType = null;
|
||||
@@ -70,7 +72,7 @@ export class VaultComponent implements OnInit {
|
||||
this.showVerifyEmail = !(await this.tokenService.getEmailVerified());
|
||||
this.showBrowserOutdated = window.navigator.userAgent.indexOf('MSIE') !== -1;
|
||||
const hasEncKey = await this.cryptoService.hasEncKey();
|
||||
this.showUpdateKey = !this.showVerifyEmail && hasEncKey;
|
||||
this.showUpdateKey = !hasEncKey;
|
||||
|
||||
this.route.queryParams.subscribe(async (params) => {
|
||||
await this.syncService.fullSync(false);
|
||||
@@ -363,6 +365,20 @@ export class VaultComponent implements OnInit {
|
||||
this.ciphersComponent.selectAll(select);
|
||||
}
|
||||
|
||||
updateKey() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.updateKeyModalRef.createComponent(factory).instance;
|
||||
this.modal.show<UpdateKeyComponent>(UpdateKeyComponent, this.updateKeyModalRef);
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
|
||||
private clearFilters() {
|
||||
this.folderId = null;
|
||||
this.collectionId = null;
|
||||
|
||||
Reference in New Issue
Block a user