1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-02-13 00:51:45 +01:00

PM-1049 - WIP of building out needed response and regular models for saving new UserDecryptionOptions on the Account in state.

This commit is contained in:
Jared Snider 2023-06-01 19:21:33 -04:00
parent 967fb959a5
commit a739422f86
No known key found for this signature in database
GPG Key ID: A149DDD612516286
13 changed files with 190 additions and 0 deletions

View File

@ -0,0 +1,5 @@
export enum UserDecryptionOption {
MASTER_PASSWORD = "masterPasswordOption",
TRUSTED_DEVICE = "trustedDeviceOption",
KEY_CONNECTOR = "keyConnectorOption",
}

View File

@ -101,6 +101,9 @@ export abstract class LogInStrategy {
protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) { protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
const accountInformation = await this.tokenService.decodeToken(tokenResponse.accessToken); const accountInformation = await this.tokenService.decodeToken(tokenResponse.accessToken);
// TODO: add AccountDecryptionOptions to the account
await this.stateService.addAccount( await this.stateService.addAccount(
new Account({ new Account({
profile: { profile: {

View File

@ -0,0 +1,11 @@
import { Jsonify } from "type-fest";
import { UserDecryptionOptionBase } from "./user-decryption-options-base.model";
export class KeyConnectorUserDecryptionOption extends UserDecryptionOptionBase {
keyConnectorUrl: string;
constructor(data: Jsonify<KeyConnectorUserDecryptionOption>) {
super(data.enabled);
this.keyConnectorUrl = data.keyConnectorUrl;
}
}

View File

@ -0,0 +1,7 @@
import { UserDecryptionOptionBase } from "./user-decryption-options-base.model";
export class MasterPasswordUserDecryptionOption extends UserDecryptionOptionBase {
constructor(enabled: boolean) {
super(enabled);
}
}

View File

@ -0,0 +1,11 @@
import { Jsonify } from "type-fest";
import { UserDecryptionOptionBase } from "./user-decryption-options-base.model";
export class TrustedDeviceUserDecryptionOption extends UserDecryptionOptionBase {
hasAdminApproval: boolean;
constructor(data: Jsonify<TrustedDeviceUserDecryptionOption>) {
super(data.enabled);
this.hasAdminApproval = data.hasAdminApproval;
}
}

View File

@ -0,0 +1,6 @@
export class UserDecryptionOptionBase {
enabled: boolean;
constructor(enabled: boolean) {
this.enabled = enabled;
}
}

View File

@ -1,7 +1,13 @@
import { KdfType } from "../../../enums"; import { KdfType } from "../../../enums";
import { BaseResponse } from "../../../models/response/base.response"; import { BaseResponse } from "../../../models/response/base.response";
import { UserDecryptionOption } from "../../enums/user-decryption-option.enum";
import { UserDecryptionOptionResponseType } from "../../types/user-decryption-option-response";
import { KeyConnectorDecryptionOptionResponse } from "./key-connector-decryption-option.response";
import { MasterPasswordDecryptionOptionResponse } from "./master-password-decryption-option.response";
import { MasterPasswordPolicyResponse } from "./master-password-policy.response"; import { MasterPasswordPolicyResponse } from "./master-password-policy.response";
import { TrustedDeviceDecryptionOptionResponse } from "./trusted-device-decryption-option.response";
import { UserDecryptionOptionResponse } from "./user-decryption-option.response";
export class IdentityTokenResponse extends BaseResponse { export class IdentityTokenResponse extends BaseResponse {
accessToken: string; accessToken: string;
@ -22,6 +28,8 @@ export class IdentityTokenResponse extends BaseResponse {
apiUseKeyConnector: boolean; apiUseKeyConnector: boolean;
keyConnectorUrl: string; keyConnectorUrl: string;
userDecryptionOptions: Array<UserDecryptionOptionResponseType>;
constructor(response: any) { constructor(response: any) {
super(response); super(response);
this.accessToken = response.access_token; this.accessToken = response.access_token;
@ -43,5 +51,27 @@ export class IdentityTokenResponse extends BaseResponse {
this.masterPasswordPolicy = new MasterPasswordPolicyResponse( this.masterPasswordPolicy = new MasterPasswordPolicyResponse(
this.getResponseProperty("MasterPasswordPolicy") this.getResponseProperty("MasterPasswordPolicy")
); );
const serverUserDecryptionOptions = this.getResponseProperty("UserDecryptionOptions");
if (serverUserDecryptionOptions) {
this.userDecryptionOptions = serverUserDecryptionOptions.map(
(serverUserDecryptionOption: any) => {
const response = new UserDecryptionOptionResponse(serverUserDecryptionOption);
switch (response.object) {
case UserDecryptionOption.MASTER_PASSWORD: {
return new MasterPasswordDecryptionOptionResponse(serverUserDecryptionOption);
}
case UserDecryptionOption.TRUSTED_DEVICE: {
return new TrustedDeviceDecryptionOptionResponse(serverUserDecryptionOption);
}
case UserDecryptionOption.KEY_CONNECTOR: {
return new KeyConnectorDecryptionOptionResponse(serverUserDecryptionOption);
}
}
}
);
}
} }
} }

View File

@ -0,0 +1,10 @@
import { UserDecryptionOptionResponse } from "./user-decryption-option.response";
export class KeyConnectorDecryptionOptionResponse extends UserDecryptionOptionResponse {
keyConnectorUrl: string;
constructor(response: any) {
super(response);
this.keyConnectorUrl = this.getResponseProperty("KeyConnectorUrl");
}
}

View File

@ -0,0 +1,7 @@
import { UserDecryptionOptionResponse } from "./user-decryption-option.response";
export class MasterPasswordDecryptionOptionResponse extends UserDecryptionOptionResponse {
constructor(response: any) {
super(response);
}
}

View File

@ -0,0 +1,10 @@
import { UserDecryptionOptionResponse } from "./user-decryption-option.response";
export class TrustedDeviceDecryptionOptionResponse extends UserDecryptionOptionResponse {
hasAdminApproval: boolean;
constructor(response: any) {
super(response);
this.hasAdminApproval = this.getResponseProperty("HasAdminApproval");
}
}

View File

@ -0,0 +1,11 @@
import { BaseResponse } from "../../../models/response/base.response";
export class UserDecryptionOptionResponse extends BaseResponse {
object: string;
constructor(response: any) {
super(response);
this.object = this.getResponseProperty("Object");
}
}

View File

@ -0,0 +1,8 @@
import { KeyConnectorDecryptionOptionResponse } from "../models/response/key-connector-decryption-option.response";
import { MasterPasswordDecryptionOptionResponse } from "../models/response/master-password-decryption-option.response";
import { TrustedDeviceDecryptionOptionResponse } from "../models/response/trusted-device-decryption-option.response";
export type UserDecryptionOptionResponseType =
| MasterPasswordDecryptionOptionResponse
| TrustedDeviceDecryptionOptionResponse
| KeyConnectorDecryptionOptionResponse;

View File

@ -8,8 +8,15 @@ import { ProviderData } from "../../admin-console/models/data/provider.data";
import { Policy } from "../../admin-console/models/domain/policy"; import { Policy } from "../../admin-console/models/domain/policy";
import { CollectionView } from "../../admin-console/models/view/collection.view"; import { CollectionView } from "../../admin-console/models/view/collection.view";
import { AuthenticationStatus } from "../../auth/enums/authentication-status"; import { AuthenticationStatus } from "../../auth/enums/authentication-status";
import { UserDecryptionOption } from "../../auth/enums/user-decryption-option.enum";
import { EnvironmentUrls } from "../../auth/models/domain/environment-urls"; import { EnvironmentUrls } from "../../auth/models/domain/environment-urls";
import { ForceResetPasswordReason } from "../../auth/models/domain/force-reset-password-reason"; import { ForceResetPasswordReason } from "../../auth/models/domain/force-reset-password-reason";
import { KeyConnectorUserDecryptionOption } from "../../auth/models/domain/user-decryption-options/key-connector-user-decryption-option.model";
import { MasterPasswordUserDecryptionOption } from "../../auth/models/domain/user-decryption-options/master-password-user-decryption-option.model";
import { TrustedDeviceUserDecryptionOption } from "../../auth/models/domain/user-decryption-options/trusted-device-user-decryption-option.model";
import { KeyConnectorDecryptionOptionResponse } from "../../auth/models/response/key-connector-decryption-option.response";
import { TrustedDeviceDecryptionOptionResponse } from "../../auth/models/response/trusted-device-decryption-option.response";
import { UserDecryptionOptionResponseType } from "../../auth/types/user-decryption-option-response";
import { KdfType, UriMatchType } from "../../enums"; import { KdfType, UriMatchType } from "../../enums";
import { Utils } from "../../misc/utils"; import { Utils } from "../../misc/utils";
import { GeneratedPasswordHistory } from "../../tools/generator/password"; import { GeneratedPasswordHistory } from "../../tools/generator/password";
@ -269,12 +276,71 @@ export class AccountTokens {
} }
} }
export class AccountDecryptionOptions {
[UserDecryptionOption.MASTER_PASSWORD]?: MasterPasswordUserDecryptionOption;
[UserDecryptionOption.TRUSTED_DEVICE]?: TrustedDeviceUserDecryptionOption;
[UserDecryptionOption.KEY_CONNECTOR]?: KeyConnectorUserDecryptionOption;
constructor(init?: Partial<AccountDecryptionOptions>) {
if (init) {
Object.assign(this, init);
}
}
static fromIdTokenResponse(
// serverUserDecryptionOptions: Array<{ Object: string; [key: string]: any }>
userDecryptionOptionResponse: Array<UserDecryptionOptionResponseType>
) {
const accountDecryptionOptions = new AccountDecryptionOptions();
// Convert UserDecryptionOptions array to dictionary
for (const optionResponse of userDecryptionOptionResponse) {
const type = optionResponse.object as UserDecryptionOption;
switch (type) {
case UserDecryptionOption.MASTER_PASSWORD:
accountDecryptionOptions[UserDecryptionOption.MASTER_PASSWORD] =
new MasterPasswordUserDecryptionOption(true);
break;
case UserDecryptionOption.TRUSTED_DEVICE:
accountDecryptionOptions[UserDecryptionOption.TRUSTED_DEVICE] =
new TrustedDeviceUserDecryptionOption({
enabled: true,
hasAdminApproval: (optionResponse as TrustedDeviceDecryptionOptionResponse)
.hasAdminApproval,
});
break;
case UserDecryptionOption.KEY_CONNECTOR:
accountDecryptionOptions[UserDecryptionOption.KEY_CONNECTOR] =
new KeyConnectorUserDecryptionOption({
enabled: true,
keyConnectorUrl: (optionResponse as KeyConnectorDecryptionOptionResponse)
.keyConnectorUrl,
});
break;
default:
continue;
}
}
return accountDecryptionOptions;
}
static fromJSON(obj: Jsonify<AccountDecryptionOptions>): AccountDecryptionOptions {
if (obj == null) {
return null;
}
return Object.assign(new AccountDecryptionOptions(), obj);
}
}
export class Account { export class Account {
data?: AccountData = new AccountData(); data?: AccountData = new AccountData();
keys?: AccountKeys = new AccountKeys(); keys?: AccountKeys = new AccountKeys();
profile?: AccountProfile = new AccountProfile(); profile?: AccountProfile = new AccountProfile();
settings?: AccountSettings = new AccountSettings(); settings?: AccountSettings = new AccountSettings();
tokens?: AccountTokens = new AccountTokens(); tokens?: AccountTokens = new AccountTokens();
decryptionOptions?: AccountDecryptionOptions = new AccountDecryptionOptions();
constructor(init: Partial<Account>) { constructor(init: Partial<Account>) {
Object.assign(this, { Object.assign(this, {
@ -298,6 +364,10 @@ export class Account {
...new AccountTokens(), ...new AccountTokens(),
...init?.tokens, ...init?.tokens,
}, },
decryptionOptions: {
...new AccountDecryptionOptions(),
...init?.decryptionOptions,
},
}); });
} }
@ -311,6 +381,7 @@ export class Account {
profile: AccountProfile.fromJSON(json?.profile), profile: AccountProfile.fromJSON(json?.profile),
settings: AccountSettings.fromJSON(json?.settings), settings: AccountSettings.fromJSON(json?.settings),
tokens: AccountTokens.fromJSON(json?.tokens), tokens: AccountTokens.fromJSON(json?.tokens),
decryptionOptions: AccountDecryptionOptions.fromJSON(json?.decryptionOptions),
}); });
} }
} }