mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-21 21:11:35 +01:00
move takeover logic to service
This commit is contained in:
parent
ed04bc65ec
commit
11a5f1a8a2
@ -1,6 +1,7 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@ -25,6 +26,7 @@ import { EmergencyAccessApiService } from "./emergency-access-api.service";
|
|||||||
import { EmergencyAccessAcceptRequest } from "./request/emergency-access-accept.request";
|
import { EmergencyAccessAcceptRequest } from "./request/emergency-access-accept.request";
|
||||||
import { EmergencyAccessConfirmRequest } from "./request/emergency-access-confirm.request";
|
import { EmergencyAccessConfirmRequest } from "./request/emergency-access-confirm.request";
|
||||||
import { EmergencyAccessInviteRequest } from "./request/emergency-access-invite.request";
|
import { EmergencyAccessInviteRequest } from "./request/emergency-access-invite.request";
|
||||||
|
import { EmergencyAccessPasswordRequest } from "./request/emergency-access-password.request";
|
||||||
import { EmergencyAccessUpdateRequest } from "./request/emergency-access-update.request";
|
import { EmergencyAccessUpdateRequest } from "./request/emergency-access-update.request";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -39,23 +41,23 @@ export class EmergencyAccessService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all emergency access that the user has been granted
|
* Gets all emergency access that the user has been granted.
|
||||||
*/
|
*/
|
||||||
async getEmergencyAccessTrusted(): Promise<EmergencyAccessGranteeView[]> {
|
async getEmergencyAccessTrusted(): Promise<EmergencyAccessGranteeView[]> {
|
||||||
return (await this.emergencyAccessApiService.getEmergencyAccessTrusted()).data;
|
return (await this.emergencyAccessApiService.getEmergencyAccessTrusted()).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all emergency access that the user has granted
|
* Gets all emergency access that the user has granted.
|
||||||
*/
|
*/
|
||||||
async getEmergencyAccessGranted(): Promise<EmergencyAccessGrantorView[]> {
|
async getEmergencyAccessGranted(): Promise<EmergencyAccessGrantorView[]> {
|
||||||
return (await this.emergencyAccessApiService.getEmergencyAccessGranted()).data;
|
return (await this.emergencyAccessApiService.getEmergencyAccessGranted()).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invites the email address to be an emergency contact
|
* Invites the email address to be an emergency contact.
|
||||||
* Step 1 of the 3 step setup flow
|
* Step 1 of the 3 step setup flow.
|
||||||
* Intended for grantor
|
* Intended for grantor.
|
||||||
* @param email email address of trusted emergency contact
|
* @param email email address of trusted emergency contact
|
||||||
* @param type type of emergency access
|
* @param type type of emergency access
|
||||||
* @param waitTimeDays number of days to wait before granting access
|
* @param waitTimeDays number of days to wait before granting access
|
||||||
@ -70,8 +72,17 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits an existing emergency access
|
* Sends another email for an existing emergency access invitation.
|
||||||
* Intended for grantor
|
* Intended for grantor.
|
||||||
|
* @param id emergency access id
|
||||||
|
*/
|
||||||
|
reinvite(id: string): Promise<void> {
|
||||||
|
return this.emergencyAccessApiService.postEmergencyAccessReinvite(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits an existing emergency access.
|
||||||
|
* Intended for grantor.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
* @param type type of emergency access
|
* @param type type of emergency access
|
||||||
* @param waitTimeDays number of days to wait before granting access
|
* @param waitTimeDays number of days to wait before granting access
|
||||||
@ -85,9 +96,9 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts an emergency access invitation
|
* Accepts an emergency access invitation.
|
||||||
* Step 2 of the 3 step setup flow
|
* Step 2 of the 3 step setup flow.
|
||||||
* Intended for grantee
|
* Intended for grantee.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
* @param token secret token provided in email
|
* @param token secret token provided in email
|
||||||
*/
|
*/
|
||||||
@ -99,9 +110,9 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts user key with grantee's public key and sends to bitwarden
|
* Encrypts user key with grantee's public key and sends to bitwarden.
|
||||||
* Step 3 of the 3 step setup flow
|
* Step 3 of the 3 step setup flow.
|
||||||
* Intended for grantor
|
* Intended for grantor.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
* @param token secret token provided in email
|
* @param token secret token provided in email
|
||||||
*/
|
*/
|
||||||
@ -128,8 +139,17 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests access to grantor's vault
|
* Deletes an existing emergency access.
|
||||||
* Intended for grantee
|
* Intended for either grantor or grantee.
|
||||||
|
* @param id emergency access id
|
||||||
|
*/
|
||||||
|
delete(id: string): Promise<void> {
|
||||||
|
return this.emergencyAccessApiService.deleteEmergencyAccess(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests access to grantor's vault.
|
||||||
|
* Intended for grantee.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
*/
|
*/
|
||||||
requestAccess(id: string): Promise<void> {
|
requestAccess(id: string): Promise<void> {
|
||||||
@ -137,8 +157,8 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Approves access to grantor's vault
|
* Approves access to grantor's vault.
|
||||||
* Intended for grantor
|
* Intended for grantor.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
*/
|
*/
|
||||||
approve(id: string): Promise<void> {
|
approve(id: string): Promise<void> {
|
||||||
@ -146,8 +166,8 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects access to grantor's vault
|
* Rejects access to grantor's vault.
|
||||||
* Intended for grantor
|
* Intended for grantor.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
*/
|
*/
|
||||||
reject(id: string): Promise<void> {
|
reject(id: string): Promise<void> {
|
||||||
@ -155,8 +175,8 @@ export class EmergencyAccessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the grantor ciphers for an emergency access in view mode
|
* Gets the grantor ciphers for an emergency access in view mode.
|
||||||
* Intended for grantee
|
* Intended for grantee.
|
||||||
* @param id emergency access id
|
* @param id emergency access id
|
||||||
*/
|
*/
|
||||||
async getViewOnlyCiphers(id: string): Promise<CipherView[]> {
|
async getViewOnlyCiphers(id: string): Promise<CipherView[]> {
|
||||||
@ -172,6 +192,44 @@ export class EmergencyAccessService {
|
|||||||
return ciphers.sort(this.cipherService.getLocaleSortingFunction());
|
return ciphers.sort(this.cipherService.getLocaleSortingFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the password for an emergency access.
|
||||||
|
* Intended for grantee.
|
||||||
|
* @param id emergency access id
|
||||||
|
* @param masterPassword new master password
|
||||||
|
* @param email email address of grantee (must be consistent or login will fail)
|
||||||
|
*/
|
||||||
|
async takeover(id: string, masterPassword: string, email: string) {
|
||||||
|
const takeoverResponse = await this.emergencyAccessApiService.postEmergencyAccessTakeover(id);
|
||||||
|
|
||||||
|
const grantorKeyBuffer = await this.cryptoService.rsaDecrypt(takeoverResponse.keyEncrypted);
|
||||||
|
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
|
||||||
|
|
||||||
|
if (grantorUserKey == null) {
|
||||||
|
throw new Error("Failed to decrypt grantor key");
|
||||||
|
}
|
||||||
|
|
||||||
|
const masterKey = await this.cryptoService.makeMasterKey(
|
||||||
|
masterPassword,
|
||||||
|
email,
|
||||||
|
takeoverResponse.kdf,
|
||||||
|
new KdfConfig(
|
||||||
|
takeoverResponse.kdfIterations,
|
||||||
|
takeoverResponse.kdfMemory,
|
||||||
|
takeoverResponse.kdfParallelism
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey);
|
||||||
|
|
||||||
|
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, grantorUserKey);
|
||||||
|
|
||||||
|
const request = new EmergencyAccessPasswordRequest();
|
||||||
|
request.newMasterPasswordHash = masterKeyHash;
|
||||||
|
request.key = encKey[1].encryptedString;
|
||||||
|
|
||||||
|
this.emergencyAccessApiService.postEmergencyAccessPassword(id, request);
|
||||||
|
}
|
||||||
|
|
||||||
async rotateEmergencyAccess(newUserKey: UserKey) {
|
async rotateEmergencyAccess(newUserKey: UserKey) {
|
||||||
const emergencyAccess = await this.emergencyAccessApiService.getEmergencyAccessTrusted();
|
const emergencyAccess = await this.emergencyAccessApiService.getEmergencyAccessTrusted();
|
||||||
// Any Invited or Accepted requests won't have the key yet, so we don't need to update them
|
// Any Invited or Accepted requests won't have the key yet, so we don't need to update them
|
||||||
|
@ -12,8 +12,6 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
|||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { EmergencyAccessStatusType } from "@bitwarden/common/auth/enums/emergency-access-status-type";
|
|
||||||
import { EmergencyAccessUpdateRequest } from "@bitwarden/common/auth/models/request/emergency-access-update.request";
|
|
||||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { UpdateKeyRequest } from "@bitwarden/common/models/request/update-key.request";
|
import { UpdateKeyRequest } from "@bitwarden/common/models/request/update-key.request";
|
||||||
@ -40,6 +38,8 @@ import { CipherWithIdRequest } from "@bitwarden/common/vault/models/request/ciph
|
|||||||
import { FolderWithIdRequest } from "@bitwarden/common/vault/models/request/folder-with-id.request";
|
import { FolderWithIdRequest } from "@bitwarden/common/vault/models/request/folder-with-id.request";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { EmergencyAccessApiService } from "../core/services/emergency-access/emergency-access-api.service";
|
import { EmergencyAccessApiService } from "../core/services/emergency-access/emergency-access-api.service";
|
||||||
|
import { EmergencyAccessStatusType } from "../core/enums/emergency-access-status-type";
|
||||||
|
import { EmergencyAccessUpdateRequest } from "../core/services/emergency-access/request/emergency-access-update.request";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-change-password",
|
selector: "app-change-password",
|
||||||
|
@ -6,8 +6,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
|||||||
import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data";
|
import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data";
|
||||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||||
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
|
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
|
||||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
|
||||||
import { EmergencyAccessPasswordRequest } from "@bitwarden/common/auth/models/request/emergency-access-password.request";
|
|
||||||
import { KdfType } from "@bitwarden/common/enums";
|
import { KdfType } from "@bitwarden/common/enums";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
@ -15,13 +13,11 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import {
|
|
||||||
SymmetricCryptoKey,
|
|
||||||
UserKey,
|
|
||||||
} from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
import { EmergencyAccessApiService } from "../../core/services/emergency-access/emergency-access-api.service";
|
import { EmergencyAccessApiService } from "../../core/services/emergency-access/emergency-access-api.service";
|
||||||
|
import { EmergencyAccessService } from "../../core/services/emergency-access/emergency-access.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "emergency-access-takeover",
|
selector: "emergency-access-takeover",
|
||||||
@ -49,6 +45,7 @@ export class EmergencyAccessTakeoverComponent
|
|||||||
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
policyService: PolicyService,
|
policyService: PolicyService,
|
||||||
|
private emergencyAccessService: EmergencyAccessService,
|
||||||
private emergencyAccessApiService: EmergencyAccessApiService,
|
private emergencyAccessApiService: EmergencyAccessApiService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
dialogService: DialogService
|
dialogService: DialogService
|
||||||
@ -91,46 +88,20 @@ export class EmergencyAccessTakeoverComponent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const takeoverResponse = await this.emergencyAccessApiService.postEmergencyAccessTakeover(
|
try {
|
||||||
this.emergencyAccessId
|
await this.emergencyAccessService.takeover(
|
||||||
);
|
this.emergencyAccessId,
|
||||||
|
this.masterPassword,
|
||||||
const oldKeyBuffer = await this.cryptoService.rsaDecrypt(takeoverResponse.keyEncrypted);
|
this.email
|
||||||
const oldUserKey = new SymmetricCryptoKey(oldKeyBuffer) as UserKey;
|
);
|
||||||
|
this.onDone.emit();
|
||||||
if (oldUserKey == null) {
|
} catch (e) {
|
||||||
|
this.logService.error(e);
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"error",
|
"error",
|
||||||
this.i18nService.t("errorOccurred"),
|
this.i18nService.t("errorOccurred"),
|
||||||
this.i18nService.t("unexpectedError")
|
this.i18nService.t("unexpectedError")
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const masterKey = await this.cryptoService.makeMasterKey(
|
|
||||||
this.masterPassword,
|
|
||||||
this.email,
|
|
||||||
takeoverResponse.kdf,
|
|
||||||
new KdfConfig(
|
|
||||||
takeoverResponse.kdfIterations,
|
|
||||||
takeoverResponse.kdfMemory,
|
|
||||||
takeoverResponse.kdfParallelism
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const masterKeyHash = await this.cryptoService.hashMasterKey(this.masterPassword, masterKey);
|
|
||||||
|
|
||||||
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, oldUserKey);
|
|
||||||
|
|
||||||
const request = new EmergencyAccessPasswordRequest();
|
|
||||||
request.newMasterPasswordHash = masterKeyHash;
|
|
||||||
request.key = encKey[1].encryptedString;
|
|
||||||
|
|
||||||
this.emergencyAccessApiService.postEmergencyAccessPassword(this.emergencyAccessId, request);
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.onDone.emit();
|
|
||||||
} catch (e) {
|
|
||||||
this.logService.error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import { DialogService } from "@bitwarden/components";
|
|||||||
|
|
||||||
import { EmergencyAccessStatusType } from "../../core/enums/emergency-access-status-type";
|
import { EmergencyAccessStatusType } from "../../core/enums/emergency-access-status-type";
|
||||||
import { EmergencyAccessType } from "../../core/enums/emergency-access-type";
|
import { EmergencyAccessType } from "../../core/enums/emergency-access-type";
|
||||||
import { EmergencyAccessApiService } from "../../core/services/emergency-access/emergency-access-api.service";
|
|
||||||
import { EmergencyAccessService } from "../../core/services/emergency-access/emergency-access.service";
|
import { EmergencyAccessService } from "../../core/services/emergency-access/emergency-access.service";
|
||||||
import {
|
import {
|
||||||
EmergencyAccessGranteeView,
|
EmergencyAccessGranteeView,
|
||||||
@ -45,7 +44,6 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
isOrganizationOwner: boolean;
|
isOrganizationOwner: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private emergencyAccessApiService: EmergencyAccessApiService,
|
|
||||||
private emergencyAccessService: EmergencyAccessService,
|
private emergencyAccessService: EmergencyAccessService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private modalService: ModalService,
|
private modalService: ModalService,
|
||||||
@ -108,7 +106,7 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
if (this.actionPromise != null) {
|
if (this.actionPromise != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.actionPromise = this.emergencyAccessApiService.postEmergencyAccessReinvite(contact.id);
|
this.actionPromise = this.emergencyAccessService.reinvite(contact.id);
|
||||||
await this.actionPromise;
|
await this.actionPromise;
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"success",
|
"success",
|
||||||
@ -179,7 +177,7 @@ export class EmergencyAccessComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.emergencyAccessApiService.deleteEmergencyAccess(details.id);
|
await this.emergencyAccessService.delete(details.id);
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
"success",
|
"success",
|
||||||
null,
|
null,
|
||||||
|
Loading…
Reference in New Issue
Block a user