mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-28950] Add enum normalizers to protect against corrupted user data in SDK mapping (#17723)
* Added normalizers to protect against corrpupted user data when mapping between client and SDK * Added comments * simplified secure note normalization
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { UriMatchType } from "@bitwarden/sdk-internal";
|
||||
|
||||
/*
|
||||
See full documentation at:
|
||||
https://bitwarden.com/help/uri-match-detection/#match-detection-options
|
||||
@@ -23,3 +25,28 @@ export type UriMatchStrategySetting = (typeof UriMatchStrategy)[keyof typeof Uri
|
||||
// using uniqueness properties of object shape over Set for ease of state storability
|
||||
export type NeverDomains = { [id: string]: null | { bannerIsDismissed?: boolean } };
|
||||
export type EquivalentDomains = string[][];
|
||||
|
||||
/**
|
||||
* Normalizes UriMatchStrategySetting for SDK mapping.
|
||||
* @param value - The URI match strategy from user data
|
||||
* @returns Valid UriMatchType or undefined if invalid
|
||||
*/
|
||||
export function normalizeUriMatchStrategyForSdk(
|
||||
value: UriMatchStrategySetting | undefined,
|
||||
): UriMatchType | undefined {
|
||||
if (value == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 0: // Domain
|
||||
case 1: // Host
|
||||
case 2: // StartsWith
|
||||
case 3: // Exact
|
||||
case 4: // RegularExpression
|
||||
case 5: // Never
|
||||
return value;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { CipherRepromptType as SdkCipherRepromptType } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { UnionOfValues } from "../types/union-of-values";
|
||||
|
||||
export const CipherRepromptType = {
|
||||
@@ -6,3 +8,20 @@ export const CipherRepromptType = {
|
||||
} as const;
|
||||
|
||||
export type CipherRepromptType = UnionOfValues<typeof CipherRepromptType>;
|
||||
|
||||
/**
|
||||
* Normalizes a CipherRepromptType value to ensure compatibility with the SDK.
|
||||
* @param value - The cipher reprompt type from user data
|
||||
* @returns Valid CipherRepromptType, defaults to CipherRepromptType.None if unrecognized
|
||||
*/
|
||||
export function normalizeCipherRepromptTypeForSdk(
|
||||
value: CipherRepromptType,
|
||||
): SdkCipherRepromptType {
|
||||
switch (value) {
|
||||
case CipherRepromptType.None:
|
||||
case CipherRepromptType.Password:
|
||||
return value;
|
||||
default:
|
||||
return CipherRepromptType.None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { FieldType as SdkFieldType } from "@bitwarden/sdk-internal";
|
||||
|
||||
const _FieldType = Object.freeze({
|
||||
Text: 0,
|
||||
Hidden: 1,
|
||||
@@ -10,3 +12,20 @@ type _FieldType = typeof _FieldType;
|
||||
export type FieldType = _FieldType[keyof _FieldType];
|
||||
|
||||
export const FieldType: Record<keyof _FieldType, FieldType> = _FieldType;
|
||||
|
||||
/**
|
||||
* Normalizes a FieldType value to ensure compatibility with the SDK.
|
||||
* @param value - The field type from user data
|
||||
* @returns Valid FieldType, defaults to FieldType.Text if unrecognized
|
||||
*/
|
||||
export function normalizeFieldTypeForSdk(value: FieldType): SdkFieldType {
|
||||
switch (value) {
|
||||
case FieldType.Text:
|
||||
case FieldType.Hidden:
|
||||
case FieldType.Boolean:
|
||||
case FieldType.Linked:
|
||||
return value;
|
||||
default:
|
||||
return FieldType.Text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { LinkedIdType as SdkLinkedIdType } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { UnionOfValues } from "../types/union-of-values";
|
||||
|
||||
export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId;
|
||||
@@ -46,3 +48,25 @@ export const IdentityLinkedId = {
|
||||
} as const;
|
||||
|
||||
export type IdentityLinkedId = UnionOfValues<typeof IdentityLinkedId>;
|
||||
|
||||
/**
|
||||
* Normalizes a LinkedIdType value to ensure compatibility with the SDK.
|
||||
* @param value - The linked ID type from user data
|
||||
* @returns Valid LinkedIdType or undefined if unrecognized
|
||||
*/
|
||||
export function normalizeLinkedIdTypeForSdk(
|
||||
value: LinkedIdType | undefined,
|
||||
): SdkLinkedIdType | undefined {
|
||||
if (value == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Check all valid LinkedId numeric values (100-418)
|
||||
const allValidValues = [
|
||||
...Object.values(LoginLinkedId),
|
||||
...Object.values(CardLinkedId),
|
||||
...Object.values(IdentityLinkedId),
|
||||
];
|
||||
|
||||
return allValidValues.includes(value) ? value : undefined;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { SecureNoteType as SdkSecureNoteType } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { UnionOfValues } from "../types/union-of-values";
|
||||
|
||||
export const SecureNoteType = {
|
||||
@@ -5,3 +7,12 @@ export const SecureNoteType = {
|
||||
} as const;
|
||||
|
||||
export type SecureNoteType = UnionOfValues<typeof SecureNoteType>;
|
||||
|
||||
/**
|
||||
* Normalizes a SecureNoteType value to ensure compatibility with the SDK.
|
||||
* @param value - The secure note type from user data
|
||||
* @returns Valid SecureNoteType, defaults to SecureNoteType.Generic if unrecognized
|
||||
*/
|
||||
export function normalizeSecureNoteTypeForSdk(value: SecureNoteType): SdkSecureNoteType {
|
||||
return SecureNoteType.Generic;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ import { Utils } from "../../../platform/misc/utils";
|
||||
import Domain from "../../../platform/models/domain/domain-base";
|
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||
import { InitializerKey } from "../../../platform/services/cryptography/initializer-key";
|
||||
import { CipherRepromptType } from "../../enums/cipher-reprompt-type";
|
||||
import {
|
||||
CipherRepromptType,
|
||||
normalizeCipherRepromptTypeForSdk,
|
||||
} from "../../enums/cipher-reprompt-type";
|
||||
import { CipherType } from "../../enums/cipher-type";
|
||||
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||
import { CipherPermissionsApi } from "../api/cipher-permissions.api";
|
||||
@@ -414,10 +417,7 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
||||
creationDate: this.creationDate.toISOString(),
|
||||
deletedDate: this.deletedDate?.toISOString(),
|
||||
archivedDate: this.archivedDate?.toISOString(),
|
||||
reprompt:
|
||||
this.reprompt === CipherRepromptType.Password
|
||||
? CipherRepromptType.Password
|
||||
: CipherRepromptType.None,
|
||||
reprompt: normalizeCipherRepromptTypeForSdk(this.reprompt),
|
||||
// Initialize all cipher-type-specific properties as undefined
|
||||
login: undefined,
|
||||
identity: undefined,
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
import { Field as SdkField, LinkedIdType as SdkLinkedIdType } from "@bitwarden/sdk-internal";
|
||||
import { Field as SdkField } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||
import Domain from "../../../platform/models/domain/domain-base";
|
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||
import { FieldType, LinkedIdType } from "../../enums";
|
||||
import {
|
||||
FieldType,
|
||||
LinkedIdType,
|
||||
normalizeFieldTypeForSdk,
|
||||
normalizeLinkedIdTypeForSdk,
|
||||
} from "../../enums";
|
||||
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||
import { FieldData } from "../data/field.data";
|
||||
import { FieldView } from "../view/field.view";
|
||||
@@ -77,9 +82,8 @@ export class Field extends Domain {
|
||||
return {
|
||||
name: this.name?.toSdk(),
|
||||
value: this.value?.toSdk(),
|
||||
type: this.type,
|
||||
// Safe type cast: client and SDK LinkedIdType enums have identical values
|
||||
linkedId: this.linkedId as unknown as SdkLinkedIdType,
|
||||
type: normalizeFieldTypeForSdk(this.type),
|
||||
linkedId: normalizeLinkedIdTypeForSdk(this.linkedId),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,10 @@ import { Jsonify } from "type-fest";
|
||||
import { LoginUri as SdkLoginUri } from "@bitwarden/sdk-internal";
|
||||
|
||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||
import { UriMatchStrategySetting } from "../../../models/domain/domain-service";
|
||||
import {
|
||||
normalizeUriMatchStrategyForSdk,
|
||||
UriMatchStrategySetting,
|
||||
} from "../../../models/domain/domain-service";
|
||||
import { Utils } from "../../../platform/misc/utils";
|
||||
import Domain from "../../../platform/models/domain/domain-base";
|
||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||
@@ -91,7 +94,7 @@ export class LoginUri extends Domain {
|
||||
return {
|
||||
uri: this.uri?.toSdk(),
|
||||
uriChecksum: this.uriChecksum?.toSdk(),
|
||||
match: this.match,
|
||||
match: normalizeUriMatchStrategyForSdk(this.match),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Jsonify } from "type-fest";
|
||||
import { SecureNote as SdkSecureNote } from "@bitwarden/sdk-internal";
|
||||
|
||||
import Domain from "../../../platform/models/domain/domain-base";
|
||||
import { SecureNoteType } from "../../enums";
|
||||
import { normalizeSecureNoteTypeForSdk, SecureNoteType } from "../../enums";
|
||||
import { SecureNoteData } from "../data/secure-note.data";
|
||||
import { SecureNoteView } from "../view/secure-note.view";
|
||||
|
||||
@@ -46,7 +46,7 @@ export class SecureNote extends Domain {
|
||||
*/
|
||||
toSdkSecureNote(): SdkSecureNote {
|
||||
return {
|
||||
type: this.type,
|
||||
type: normalizeSecureNoteTypeForSdk(this.type),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user