mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +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:
|
See full documentation at:
|
||||||
https://bitwarden.com/help/uri-match-detection/#match-detection-options
|
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
|
// using uniqueness properties of object shape over Set for ease of state storability
|
||||||
export type NeverDomains = { [id: string]: null | { bannerIsDismissed?: boolean } };
|
export type NeverDomains = { [id: string]: null | { bannerIsDismissed?: boolean } };
|
||||||
export type EquivalentDomains = string[][];
|
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";
|
import { UnionOfValues } from "../types/union-of-values";
|
||||||
|
|
||||||
export const CipherRepromptType = {
|
export const CipherRepromptType = {
|
||||||
@@ -6,3 +8,20 @@ export const CipherRepromptType = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type CipherRepromptType = UnionOfValues<typeof CipherRepromptType>;
|
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({
|
const _FieldType = Object.freeze({
|
||||||
Text: 0,
|
Text: 0,
|
||||||
Hidden: 1,
|
Hidden: 1,
|
||||||
@@ -10,3 +12,20 @@ type _FieldType = typeof _FieldType;
|
|||||||
export type FieldType = _FieldType[keyof _FieldType];
|
export type FieldType = _FieldType[keyof _FieldType];
|
||||||
|
|
||||||
export const FieldType: Record<keyof _FieldType, FieldType> = _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";
|
import { UnionOfValues } from "../types/union-of-values";
|
||||||
|
|
||||||
export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId;
|
export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId;
|
||||||
@@ -46,3 +48,25 @@ export const IdentityLinkedId = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type IdentityLinkedId = UnionOfValues<typeof IdentityLinkedId>;
|
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";
|
import { UnionOfValues } from "../types/union-of-values";
|
||||||
|
|
||||||
export const SecureNoteType = {
|
export const SecureNoteType = {
|
||||||
@@ -5,3 +7,12 @@ export const SecureNoteType = {
|
|||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type SecureNoteType = UnionOfValues<typeof SecureNoteType>;
|
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 Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
import { InitializerKey } from "../../../platform/services/cryptography/initializer-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 { CipherType } from "../../enums/cipher-type";
|
||||||
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
import { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { CipherPermissionsApi } from "../api/cipher-permissions.api";
|
import { CipherPermissionsApi } from "../api/cipher-permissions.api";
|
||||||
@@ -414,10 +417,7 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
|
|||||||
creationDate: this.creationDate.toISOString(),
|
creationDate: this.creationDate.toISOString(),
|
||||||
deletedDate: this.deletedDate?.toISOString(),
|
deletedDate: this.deletedDate?.toISOString(),
|
||||||
archivedDate: this.archivedDate?.toISOString(),
|
archivedDate: this.archivedDate?.toISOString(),
|
||||||
reprompt:
|
reprompt: normalizeCipherRepromptTypeForSdk(this.reprompt),
|
||||||
this.reprompt === CipherRepromptType.Password
|
|
||||||
? CipherRepromptType.Password
|
|
||||||
: CipherRepromptType.None,
|
|
||||||
// Initialize all cipher-type-specific properties as undefined
|
// Initialize all cipher-type-specific properties as undefined
|
||||||
login: undefined,
|
login: undefined,
|
||||||
identity: undefined,
|
identity: undefined,
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { Jsonify } from "type-fest";
|
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 { EncString } from "../../../key-management/crypto/models/enc-string";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
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 { conditionalEncString, encStringFrom } from "../../utils/domain-utils";
|
||||||
import { FieldData } from "../data/field.data";
|
import { FieldData } from "../data/field.data";
|
||||||
import { FieldView } from "../view/field.view";
|
import { FieldView } from "../view/field.view";
|
||||||
@@ -77,9 +82,8 @@ export class Field extends Domain {
|
|||||||
return {
|
return {
|
||||||
name: this.name?.toSdk(),
|
name: this.name?.toSdk(),
|
||||||
value: this.value?.toSdk(),
|
value: this.value?.toSdk(),
|
||||||
type: this.type,
|
type: normalizeFieldTypeForSdk(this.type),
|
||||||
// Safe type cast: client and SDK LinkedIdType enums have identical values
|
linkedId: normalizeLinkedIdTypeForSdk(this.linkedId),
|
||||||
linkedId: this.linkedId as unknown as SdkLinkedIdType,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import { Jsonify } from "type-fest";
|
|||||||
import { LoginUri as SdkLoginUri } from "@bitwarden/sdk-internal";
|
import { LoginUri as SdkLoginUri } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import { EncString } from "../../../key-management/crypto/models/enc-string";
|
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 { Utils } from "../../../platform/misc/utils";
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
import Domain from "../../../platform/models/domain/domain-base";
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
||||||
@@ -91,7 +94,7 @@ export class LoginUri extends Domain {
|
|||||||
return {
|
return {
|
||||||
uri: this.uri?.toSdk(),
|
uri: this.uri?.toSdk(),
|
||||||
uriChecksum: this.uriChecksum?.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 { SecureNote as SdkSecureNote } from "@bitwarden/sdk-internal";
|
||||||
|
|
||||||
import Domain from "../../../platform/models/domain/domain-base";
|
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 { SecureNoteData } from "../data/secure-note.data";
|
||||||
import { SecureNoteView } from "../view/secure-note.view";
|
import { SecureNoteView } from "../view/secure-note.view";
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export class SecureNote extends Domain {
|
|||||||
*/
|
*/
|
||||||
toSdkSecureNote(): SdkSecureNote {
|
toSdkSecureNote(): SdkSecureNote {
|
||||||
return {
|
return {
|
||||||
type: this.type,
|
type: normalizeSecureNoteTypeForSdk(this.type),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user