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

[PM-11619] Replace client-side feature flag with server-side flag (#10709)

This commit is contained in:
Todd Martin 2024-09-06 09:25:15 -04:00 committed by GitHub
parent f0fe397307
commit 03b3345bf6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 27 additions and 53 deletions

View File

@ -2,7 +2,6 @@
"devFlags": {}, "devFlags": {},
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true,
"enableCipherKeyEncryption": false,
"accountSwitching": false "accountSwitching": false
} }
} }

View File

@ -7,7 +7,6 @@
}, },
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true,
"enableCipherKeyEncryption": false,
"accountSwitching": true "accountSwitching": true
} }
} }

View File

@ -1,6 +1,5 @@
{ {
"flags": { "flags": {
"enableCipherKeyEncryption": false,
"accountSwitching": true "accountSwitching": true
} }
} }

View File

@ -1,5 +1,3 @@
{ {
"flags": { "flags": {}
"enableCipherKeyEncryption": false
}
} }

View File

@ -1,5 +1,3 @@
{ {
"flags": { "flags": {}
"enableCipherKeyEncryption": false
}
} }

View File

@ -1,6 +1,4 @@
{ {
"devFlags": {}, "devFlags": {},
"flags": { "flags": {}
"enableCipherKeyEncryption": false
}
} }

View File

@ -1,6 +1,4 @@
{ {
"devFlags": {}, "devFlags": {},
"flags": { "flags": {}
"enableCipherKeyEncryption": false
}
} }

View File

@ -1,5 +1,3 @@
{ {
"flags": { "flags": {}
"enableCipherKeyEncryption": false
}
} }

View File

@ -11,7 +11,6 @@
"allowedHosts": "auto" "allowedHosts": "auto"
}, },
"flags": { "flags": {
"showPasswordless": false, "showPasswordless": false
"enableCipherKeyEncryption": false
} }
} }

View File

@ -17,7 +17,6 @@
"proxyNotifications": "https://notifications.bitwarden.com" "proxyNotifications": "https://notifications.bitwarden.com"
}, },
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true
"enableCipherKeyEncryption": false
} }
} }

View File

@ -20,8 +20,7 @@
} }
], ],
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true
"enableCipherKeyEncryption": false
}, },
"devFlags": {} "devFlags": {}
} }

View File

@ -11,7 +11,6 @@
"buttonAction": "https://www.paypal.com/cgi-bin/webscr" "buttonAction": "https://www.paypal.com/cgi-bin/webscr"
}, },
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true
"enableCipherKeyEncryption": false
} }
} }

View File

@ -27,7 +27,6 @@
} }
], ],
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true
"enableCipherKeyEncryption": false
} }
} }

View File

@ -7,7 +7,6 @@
"port": 8081 "port": 8081
}, },
"flags": { "flags": {
"showPasswordless": true, "showPasswordless": true
"enableCipherKeyEncryption": false
} }
} }

View File

@ -34,6 +34,7 @@ export enum FeatureFlag {
AccountDeprovisioning = "pm-10308-account-deprovisioning", AccountDeprovisioning = "pm-10308-account-deprovisioning",
NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements", NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements",
AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api", AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api",
CipherKeyEncryption = "cipher-key-encryption",
} }
export type AllowedFeatureFlagTypes = boolean | number | string; export type AllowedFeatureFlagTypes = boolean | number | string;
@ -78,6 +79,7 @@ export const DefaultFeatureFlagValue = {
[FeatureFlag.AccountDeprovisioning]: FALSE, [FeatureFlag.AccountDeprovisioning]: FALSE,
[FeatureFlag.NotificationBarAddLoginImprovements]: FALSE, [FeatureFlag.NotificationBarAddLoginImprovements]: FALSE,
[FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE, [FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE,
[FeatureFlag.CipherKeyEncryption]: FALSE,
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>; } satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;

View File

@ -2,7 +2,6 @@
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
export type SharedFlags = { export type SharedFlags = {
showPasswordless?: boolean; showPasswordless?: boolean;
enableCipherKeyEncryption?: boolean;
}; };
// required to avoid linting errors when there are no flags // required to avoid linting errors when there are no flags

View File

@ -166,7 +166,7 @@ describe("Cipher Service", () => {
); );
configService.checkServerMeetsVersionRequirement$.mockReturnValue(of(false)); configService.checkServerMeetsVersionRequirement$.mockReturnValue(of(false));
setEncryptionKeyFlag(false); configService.getFeatureFlag.mockResolvedValue(false);
const spy = jest.spyOn(cipherFileUploadService, "upload"); const spy = jest.spyOn(cipherFileUploadService, "upload");
@ -298,16 +298,16 @@ describe("Cipher Service", () => {
}); });
describe("cipher.key", () => { describe("cipher.key", () => {
it("is null when enableCipherKeyEncryption flag is false", async () => { it("is null when feature flag is false", async () => {
setEncryptionKeyFlag(false); configService.getFeatureFlag.mockResolvedValue(false);
const cipher = await cipherService.encrypt(cipherView, userId); const cipher = await cipherService.encrypt(cipherView, userId);
expect(cipher.key).toBeNull(); expect(cipher.key).toBeNull();
}); });
it("is defined when enableCipherKeyEncryption flag is true", async () => { it("is defined when feature flag flag is true", async () => {
setEncryptionKeyFlag(true); configService.getFeatureFlag.mockResolvedValue(true);
const cipher = await cipherService.encrypt(cipherView, userId); const cipher = await cipherService.encrypt(cipherView, userId);
@ -320,16 +320,16 @@ describe("Cipher Service", () => {
jest.spyOn<any, string>(cipherService, "encryptCipherWithCipherKey"); jest.spyOn<any, string>(cipherService, "encryptCipherWithCipherKey");
}); });
it("is not called when enableCipherKeyEncryption is false", async () => { it("is not called when feature flag is false", async () => {
setEncryptionKeyFlag(false); configService.getFeatureFlag.mockResolvedValue(false);
await cipherService.encrypt(cipherView, userId); await cipherService.encrypt(cipherView, userId);
expect(cipherService["encryptCipherWithCipherKey"]).not.toHaveBeenCalled(); expect(cipherService["encryptCipherWithCipherKey"]).not.toHaveBeenCalled();
}); });
it("is called when enableCipherKeyEncryption is true", async () => { it("is called when feature flag is true", async () => {
setEncryptionKeyFlag(true); configService.getFeatureFlag.mockResolvedValue(true);
await cipherService.encrypt(cipherView, userId); await cipherService.encrypt(cipherView, userId);
@ -345,7 +345,7 @@ describe("Cipher Service", () => {
let encryptedKey: EncString; let encryptedKey: EncString;
beforeEach(() => { beforeEach(() => {
setEncryptionKeyFlag(true); configService.getFeatureFlag.mockResolvedValue(true);
configService.checkServerMeetsVersionRequirement$.mockReturnValue(of(true)); configService.checkServerMeetsVersionRequirement$.mockReturnValue(of(true));
searchService.indexedEntityId$ = of(null); searchService.indexedEntityId$ = of(null);
@ -398,9 +398,3 @@ describe("Cipher Service", () => {
}); });
}); });
}); });
function setEncryptionKeyFlag(value: boolean) {
process.env.FLAGS = JSON.stringify({
enableCipherKeyEncryption: value,
});
}

View File

@ -17,7 +17,6 @@ import { CryptoService } from "../../platform/abstractions/crypto.service";
import { EncryptService } from "../../platform/abstractions/encrypt.service"; import { EncryptService } from "../../platform/abstractions/encrypt.service";
import { I18nService } from "../../platform/abstractions/i18n.service"; import { I18nService } from "../../platform/abstractions/i18n.service";
import { StateService } from "../../platform/abstractions/state.service"; import { StateService } from "../../platform/abstractions/state.service";
import { flagEnabled } from "../../platform/misc/flags";
import { sequentialize } from "../../platform/misc/sequentialize"; import { sequentialize } from "../../platform/misc/sequentialize";
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";
@ -1662,11 +1661,10 @@ export class CipherService implements CipherServiceAbstraction {
} }
private async getCipherKeyEncryptionEnabled(): Promise<boolean> { private async getCipherKeyEncryptionEnabled(): Promise<boolean> {
return ( const featureEnabled = await this.configService.getFeatureFlag(FeatureFlag.CipherKeyEncryption);
flagEnabled("enableCipherKeyEncryption") && const meetsServerVersion = await firstValueFrom(
(await firstValueFrom(
this.configService.checkServerMeetsVersionRequirement$(CIPHER_KEY_ENC_MIN_SERVER_VER), this.configService.checkServerMeetsVersionRequirement$(CIPHER_KEY_ENC_MIN_SERVER_VER),
))
); );
return featureEnabled && meetsServerVersion;
} }
} }