1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00

[PM-14445] TS strict for Key Management, Keys and Lock component (#13121)

* PM-14445: TS strict for Key Management Biometrics

* formatting

* callbacks not null expectations

* state nullability expectations updates

* unit tests fix

* secure channel naming, explicit null check on messageId

* KM-14445: TS strict for Key Management, Keys and Lock component

* conflicts resolution, new strict check failures

* null simplifications

* migrate legacy encryption when no active user throw error instead of hiding it

* throw instead of return
This commit is contained in:
Maciej Zieniuk
2025-02-20 18:45:37 +01:00
committed by GitHub
parent ca41ecba29
commit 3924bc9c84
29 changed files with 403 additions and 279 deletions

View File

@@ -58,6 +58,9 @@ export class ProviderEncryptedOrganizationKey implements BaseEncryptedOrganizati
new EncString(this.key),
providerKeys[this.providerId],
);
if (decValue == null) {
throw new Error("Failed to decrypt organization key");
}
return new SymmetricCryptoKey(decValue) as OrgKey;
}

View File

@@ -13,9 +13,9 @@ export class FakeMasterPasswordService implements InternalMasterPasswordServiceA
mock = mock<InternalMasterPasswordServiceAbstraction>();
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
masterKeySubject = new ReplaySubject<MasterKey>(1);
masterKeySubject = new ReplaySubject<MasterKey | null>(1);
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
masterKeyHashSubject = new ReplaySubject<string>(1);
masterKeyHashSubject = new ReplaySubject<string | null>(1);
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
forceSetPasswordReasonSubject = new ReplaySubject<ForceSetPasswordReason>(1);

View File

@@ -22,5 +22,5 @@ export type ServerSideVerification = OtpVerification | MasterPasswordVerificatio
export type MasterPasswordVerificationResponse = {
masterKey: MasterKey;
policyOptions: MasterPasswordPolicyResponse;
policyOptions: MasterPasswordPolicyResponse | null;
};

View File

@@ -33,7 +33,7 @@ export abstract class EncryptService {
encThing: Encrypted,
key: SymmetricCryptoKey,
decryptTrace?: string,
): Promise<Uint8Array>;
): Promise<Uint8Array | null>;
abstract rsaEncrypt(data: Uint8Array, publicKey: Uint8Array): Promise<EncString>;
abstract rsaDecrypt(data: EncString, privateKey: Uint8Array): Promise<Uint8Array>;
abstract resolveLegacyKey(key: SymmetricCryptoKey, encThing: Encrypted): SymmetricCryptoKey;

View File

@@ -136,7 +136,7 @@ export class EncryptServiceImplementation implements EncryptService {
encThing: Encrypted,
key: SymmetricCryptoKey,
decryptContext: string = "no context",
): Promise<Uint8Array> {
): Promise<Uint8Array | null> {
if (key == null) {
throw new Error("No encryption key provided.");
}

View File

@@ -30,7 +30,7 @@ export abstract class StateService<T extends Account = Account> {
/**
* Sets the user's auto key
*/
setUserKeyAutoUnlock: (value: string, options?: StorageOptions) => Promise<void>;
setUserKeyAutoUnlock: (value: string | null, options?: StorageOptions) => Promise<void>;
/**
* Gets the user's biometric key
*/
@@ -57,7 +57,7 @@ export abstract class StateService<T extends Account = Account> {
/**
* @deprecated For migration purposes only, use setUserKeyAuto instead
*/
setCryptoMasterKeyAuto: (value: string, options?: StorageOptions) => Promise<void>;
setCryptoMasterKeyAuto: (value: string | null, options?: StorageOptions) => Promise<void>;
getDuckDuckGoSharedKey: (options?: StorageOptions) => Promise<string>;
setDuckDuckGoSharedKey: (value: string, options?: StorageOptions) => Promise<void>;

View File

@@ -8,7 +8,7 @@ import { ObservableInput, OperatorFunction, map } from "rxjs";
*/
export function convertValues<TKey extends PropertyKey, TInput, TOutput>(
project: (key: TKey, value: TInput) => ObservableInput<TOutput>,
): OperatorFunction<Record<TKey, TInput>, Record<TKey, ObservableInput<TOutput>>> {
): OperatorFunction<Record<TKey, TInput> | null, Record<TKey, ObservableInput<TOutput>>> {
return map((inputRecord) => {
if (inputRecord == null) {
return null;

View File

@@ -158,7 +158,11 @@ export class EncString implements Encrypted {
return EXPECTED_NUM_PARTS_BY_ENCRYPTION_TYPE[encType] === encPieces.length;
}
async decrypt(orgId: string, key: SymmetricCryptoKey = null, context?: string): Promise<string> {
async decrypt(
orgId: string | null,
key: SymmetricCryptoKey = null,
context?: string,
): Promise<string> {
if (this.decryptedValue != null) {
return this.decryptedValue;
}

View File

@@ -170,7 +170,7 @@ export class StateService<
/**
* user key when using the "never" option of vault timeout
*/
async setUserKeyAutoUnlock(value: string, options?: StorageOptions): Promise<void> {
async setUserKeyAutoUnlock(value: string | null, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "auto" }),
await this.defaultSecureStorageOptions(),
@@ -226,7 +226,7 @@ export class StateService<
/**
* @deprecated Use UserKeyAuto instead
*/
async setCryptoMasterKeyAuto(value: string, options?: StorageOptions): Promise<void> {
async setCryptoMasterKeyAuto(value: string | null, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(
this.reconcileOptions(options, { keySuffix: "auto" }),
await this.defaultSecureStorageOptions(),
@@ -663,7 +663,7 @@ export class StateService<
protected async saveSecureStorageKey<T extends JsonValue>(
key: string,
value: T,
value: T | null,
options?: StorageOptions,
) {
return value == null