```ts
export type FooDialogParams = {
bar: string;
@@ -157,9 +157,9 @@ fully migrated should have no reference to the `ModalService`.
4. Replace calls to `ModalService.open` or `ModalService.openViewRef` with the newly created static
`open` method:
-
`this.modalService.open(FooDialogComponent);`
+
`this.modalService.open(FooDialogComponent);`
-
`FooDialogComponent.open(this.dialogService);`
+
`FooDialogComponent.open(this.dialogService);`
## Examples
diff --git a/libs/components/src/tabs/shared/tab-list-item.directive.ts b/libs/components/src/tabs/shared/tab-list-item.directive.ts
index 74a87b1d29..4b2030388f 100644
--- a/libs/components/src/tabs/shared/tab-list-item.directive.ts
+++ b/libs/components/src/tabs/shared/tab-list-item.directive.ts
@@ -42,7 +42,7 @@ export class TabListItemDirective implements FocusableOption {
return ["!tw-text-muted", "hover:!tw-text-muted"];
}
if (this.active) {
- return ["!tw-text-primary-500", "hover:!tw-text-primary-700"];
+ return ["!tw-text-primary-600", "hover:!tw-text-primary-700"];
}
return ["!tw-text-main", "hover:!tw-text-main"];
}
@@ -78,7 +78,7 @@ export class TabListItemDirective implements FocusableOption {
return [
"tw--mb-px",
"tw-border-x-secondary-300",
- "tw-border-t-primary-500",
+ "tw-border-t-primary-600",
"tw-border-b",
"tw-border-b-background",
"!tw-bg-background",
diff --git a/libs/components/src/toggle-group/toggle.component.ts b/libs/components/src/toggle-group/toggle.component.ts
index 55c678d017..7d227acde3 100644
--- a/libs/components/src/toggle-group/toggle.component.ts
+++ b/libs/components/src/toggle-group/toggle.component.ts
@@ -50,10 +50,10 @@ export class ToggleComponent
{
"peer-focus:tw-outline-none",
"peer-focus:tw-ring",
"peer-focus:tw-ring-offset-2",
- "peer-focus:tw-ring-primary-500",
+ "peer-focus:tw-ring-primary-600",
"peer-focus:tw-z-10",
- "peer-focus:tw-bg-primary-500",
- "peer-focus:tw-border-primary-500",
+ "peer-focus:tw-bg-primary-600",
+ "peer-focus:tw-border-primary-600",
"peer-focus:!tw-text-contrast",
"hover:tw-no-underline",
@@ -61,8 +61,8 @@ export class ToggleComponent {
"hover:tw-border-text-muted",
"hover:!tw-text-contrast",
- "peer-checked:tw-bg-primary-500",
- "peer-checked:tw-border-primary-500",
+ "peer-checked:tw-bg-primary-600",
+ "peer-checked:tw-border-primary-600",
"peer-checked:!tw-text-contrast",
"tw-py-1.5",
"tw-px-3",
diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css
index 75a8fa6380..0087af28ae 100644
--- a/libs/components/src/tw-theme.css
+++ b/libs/components/src/tw-theme.css
@@ -1,5 +1,13 @@
@import "./reset.css";
+/**
+ Note that the value of the *-600 colors is currently equivalent to the value
+ of the *-500 variant of that color. This is a temporary change to make BW-42
+ updates easier.
+
+ TODO remove comment when the color palette portion of BW-42 is completed.
+*/
+
:root {
--color-transparent-hover: rgb(0 0 0 / 0.03);
@@ -10,24 +18,24 @@
--color-background-alt4: 13 60 119;
--color-primary-300: 103 149 232;
- --color-primary-500: 23 93 220;
+ --color-primary-600: 23 93 220;
--color-primary-700: 18 82 163;
--color-secondary-100: 240 240 240;
--color-secondary-300: 206 212 220;
- --color-secondary-500: 137 146 159;
+ --color-secondary-600: 137 146 159;
--color-secondary-700: 33 37 41;
- --color-success-500: 1 126 69;
+ --color-success-600: 1 126 69;
--color-success-700: 0 85 46;
- --color-danger-500: 200 53 34;
+ --color-danger-600: 200 53 34;
--color-danger-700: 152 41 27;
- --color-warning-500: 139 102 9;
+ --color-warning-600: 139 102 9;
--color-warning-700: 105 77 5;
- --color-info-500: 85 85 85;
+ --color-info-600: 85 85 85;
--color-info-700: 59 58 58;
--color-text-main: 33 37 41;
@@ -53,24 +61,24 @@
--color-background-alt4: 16 18 21;
--color-primary-300: 23 93 220;
- --color-primary-500: 106 153 240;
+ --color-primary-600: 106 153 240;
--color-primary-700: 180 204 249;
--color-secondary-100: 47 52 61;
--color-secondary-300: 110 118 137;
- --color-secondary-500: 186 192 206;
+ --color-secondary-600: 186 192 206;
--color-secondary-700: 255 255 255;
- --color-success-500: 82 224 124;
+ --color-success-600: 82 224 124;
--color-success-700: 168 239 190;
- --color-danger-500: 255 141 133;
+ --color-danger-600: 255 141 133;
--color-danger-700: 255 191 187;
- --color-warning-500: 255 235 102;
+ --color-warning-600: 255 235 102;
--color-warning-700: 255 245 179;
- --color-info-500: 164 176 198;
+ --color-info-600: 164 176 198;
--color-info-700: 209 215 226;
--color-text-main: 255 255 255;
@@ -92,24 +100,24 @@
--color-background-alt4: 67 76 94;
--color-primary-300: 108 153 166;
- --color-primary-500: 136 192 208;
+ --color-primary-600: 136 192 208;
--color-primary-700: 160 224 242;
--color-secondary-100: 76 86 106;
--color-secondary-300: 94 105 125;
- --color-secondary-500: 216 222 233;
+ --color-secondary-600: 216 222 233;
--color-secondary-700: 255 255 255;
- --color-success-500: 163 190 140;
+ --color-success-600: 163 190 140;
--color-success-700: 144 170 122;
- --color-danger-500: 228 129 139;
+ --color-danger-600: 228 129 139;
--color-danger-700: 191 97 106;
- --color-warning-500: 235 203 139;
+ --color-warning-600: 235 203 139;
--color-warning-700: 210 181 121;
- --color-info-500: 129 161 193;
+ --color-info-600: 129 161 193;
--color-info-700: 94 129 172;
--color-text-main: 229 233 240;
@@ -131,24 +139,24 @@
--color-background-alt4: 0 43 54;
--color-primary-300: 42 161 152;
- --color-primary-500: 133 153 0;
+ --color-primary-600: 133 153 0;
--color-primary-700: 192 203 123;
--color-secondary-100: 31 72 87;
--color-secondary-300: 101 123 131;
- --color-secondary-500: 131 148 150;
+ --color-secondary-600: 131 148 150;
--color-secondary-700: 238 232 213;
- --color-success-500: 133 153 0;
+ --color-success-600: 133 153 0;
--color-success-700: 192 203 123;
- --color-danger-500: 220 50 47;
+ --color-danger-600: 220 50 47;
--color-danger-700: 223 135 134;
- --color-warning-500: 181 137 0;
+ --color-warning-600: 181 137 0;
--color-warning-700: 220 189 92;
- --color-info-500: 133 153 0;
+ --color-info-600: 133 153 0;
--color-info-700: 192 203 123;
--color-text-main: 253 246 227;
diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js
index 5f49c6fc26..b76f25eae7 100644
--- a/libs/components/tailwind.config.base.js
+++ b/libs/components/tailwind.config.base.js
@@ -25,29 +25,29 @@ module.exports = {
black: colors.black,
primary: {
300: rgba("--color-primary-300"),
- 500: rgba("--color-primary-500"),
+ 600: rgba("--color-primary-600"),
700: rgba("--color-primary-700"),
},
secondary: {
100: rgba("--color-secondary-100"),
300: rgba("--color-secondary-300"),
- 500: rgba("--color-secondary-500"),
+ 600: rgba("--color-secondary-600"),
700: rgba("--color-secondary-700"),
},
success: {
- 500: rgba("--color-success-500"),
+ 600: rgba("--color-success-600"),
700: rgba("--color-success-700"),
},
danger: {
- 500: rgba("--color-danger-500"),
+ 600: rgba("--color-danger-600"),
700: rgba("--color-danger-700"),
},
warning: {
- 500: rgba("--color-warning-500"),
+ 600: rgba("--color-warning-600"),
700: rgba("--color-warning-700"),
},
info: {
- 500: rgba("--color-info-500"),
+ 600: rgba("--color-info-600"),
700: rgba("--color-info-700"),
},
text: {
@@ -71,13 +71,13 @@ module.exports = {
contrast: rgba("--color-text-contrast"),
alt2: rgba("--color-text-alt2"),
code: rgba("--color-text-code"),
- success: rgba("--color-success-500"),
- danger: rgba("--color-danger-500"),
- warning: rgba("--color-warning-500"),
- info: rgba("--color-info-500"),
+ success: rgba("--color-success-600"),
+ danger: rgba("--color-danger-600"),
+ warning: rgba("--color-warning-600"),
+ info: rgba("--color-info-600"),
primary: {
300: rgba("--color-primary-300"),
- 500: rgba("--color-primary-500"),
+ 600: rgba("--color-primary-600"),
700: rgba("--color-primary-700"),
},
},
From cbf48decec39c84b8b0a8dd30f898386cae361df Mon Sep 17 00:00:00 2001
From: Shane Melton
Date: Fri, 5 Apr 2024 08:23:50 -0700
Subject: [PATCH 04/10] [PM-7292] Fix viewing/editing unassigned ciphers for
admins (#8627)
* [PM-7292] Introduce canEditUnassignedCiphers helper
* [PM-7292] Use new canEditUnassignedCiphers helper
* [PM-7292] Remove duplicate canUseAdminCollections helper
---
apps/web/src/app/vault/org-vault/vault.component.ts | 12 +++++-------
.../src/vault/components/add-edit.component.ts | 2 +-
.../src/admin-console/models/domain/organization.ts | 5 +++--
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/apps/web/src/app/vault/org-vault/vault.component.ts b/apps/web/src/app/vault/org-vault/vault.component.ts
index e4860f2dbc..d7cc70c583 100644
--- a/apps/web/src/app/vault/org-vault/vault.component.ts
+++ b/apps/web/src/app/vault/org-vault/vault.component.ts
@@ -213,7 +213,7 @@ export class VaultComponent implements OnInit, OnDestroy {
switchMap(async ([organization]) => {
this.organization = organization;
- if (!organization.canUseAdminCollections(this.flexibleCollectionsV1Enabled)) {
+ if (!organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled)) {
await this.syncService.fullSync(false);
}
@@ -407,8 +407,7 @@ export class VaultComponent implements OnInit, OnDestroy {
]).pipe(
map(([filter, collection, organization]) => {
return (
- (filter.collectionId === Unassigned &&
- !organization.canUseAdminCollections(this.flexibleCollectionsV1Enabled)) ||
+ (filter.collectionId === Unassigned && !organization.canEditUnassignedCiphers()) ||
(!organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled) &&
collection != undefined &&
!collection.node.assigned)
@@ -454,12 +453,11 @@ export class VaultComponent implements OnInit, OnDestroy {
map(([filter, collection, organization]) => {
return (
// Filtering by unassigned, show message if not admin
- (filter.collectionId === Unassigned &&
- !organization.canUseAdminCollections(this.flexibleCollectionsV1Enabled)) ||
+ (filter.collectionId === Unassigned && !organization.canEditUnassignedCiphers()) ||
// Filtering by a collection, so show message if user is not assigned
(collection != undefined &&
!collection.node.assigned &&
- !organization.canUseAdminCollections(this.flexibleCollectionsV1Enabled))
+ !organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled))
);
}),
shareReplay({ refCount: true, bufferSize: 1 }),
@@ -482,7 +480,7 @@ export class VaultComponent implements OnInit, OnDestroy {
(await firstValueFrom(allCipherMap$))[cipherId] != undefined;
} else {
canEditCipher =
- organization.canUseAdminCollections(this.flexibleCollectionsV1Enabled) ||
+ organization.canEditAnyCollection(this.flexibleCollectionsV1Enabled) ||
(await this.cipherService.get(cipherId)) != null;
}
diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts
index 36182ed9cf..6a0cfde350 100644
--- a/libs/angular/src/vault/components/add-edit.component.ts
+++ b/libs/angular/src/vault/components/add-edit.component.ts
@@ -662,7 +662,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
// if a cipher is unassigned we want to check if they are an admin or have permission to edit any collection
if (!cipher.collectionIds) {
- orgAdmin = this.organization?.canEditAllCiphers(this.flexibleCollectionsV1Enabled);
+ orgAdmin = this.organization?.canEditUnassignedCiphers();
}
return this.cipher.id == null
diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts
index 5850f4582e..bdf0b8fbbf 100644
--- a/libs/common/src/admin-console/models/domain/organization.ts
+++ b/libs/common/src/admin-console/models/domain/organization.ts
@@ -203,8 +203,9 @@ export class Organization {
);
}
- canUseAdminCollections(flexibleCollectionsV1Enabled: boolean) {
- return this.canEditAnyCollection(flexibleCollectionsV1Enabled);
+ canEditUnassignedCiphers() {
+ // TODO: Update this to exclude Providers if provider access is restricted in AC-1707
+ return this.isAdmin || this.permissions.editAnyCollection;
}
canEditAllCiphers(flexibleCollectionsV1Enabled: boolean) {
From 574285abd008dc99fe8d413269312a0c5b085155 Mon Sep 17 00:00:00 2001
From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
Date: Fri, 5 Apr 2024 11:34:25 -0500
Subject: [PATCH 05/10] [SM-1159] Use correct i18n key (#8630)
---
.../projects/service-account-projects.component.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/projects/service-account-projects.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/projects/service-account-projects.component.html
index 772579426a..b97c5ef114 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/projects/service-account-projects.component.html
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/projects/service-account-projects.component.html
@@ -8,7 +8,7 @@
[label]="'projects' | i18n"
[hint]="'newSaSelectAccess' | i18n"
[columnTitle]="'projects' | i18n"
- [emptyMessage]="'serviceAccountEmptyProjectAccessPolicies' | i18n"
+ [emptyMessage]="'serviceAccountEmptyProjectAccesspolicies' | i18n"
(onCreateAccessPolicies)="handleCreateAccessPolicies($event)"
(onDeleteAccessPolicy)="handleDeleteAccessPolicy($event)"
(onUpdateAccessPolicy)="handleUpdateAccessPolicy($event)"
From edf35a9ad1d1d4fe22b7462b80ed53a6f319ab7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?=
Date: Fri, 5 Apr 2024 13:03:04 -0400
Subject: [PATCH 06/10] fix fencepost errors in padded data packer (#8631)
Unit tests trim vertical pipes when appear in the data packer's JSON data, but electron is not as forgiving. It throws errors in this situation. This fixes the error by trimming the pipes before b64 decoding the result.
---
.../tools/generator/state/padded-data-packer.ts | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/libs/common/src/tools/generator/state/padded-data-packer.ts b/libs/common/src/tools/generator/state/padded-data-packer.ts
index e2f5058b21..d1573e5cb7 100644
--- a/libs/common/src/tools/generator/state/padded-data-packer.ts
+++ b/libs/common/src/tools/generator/state/padded-data-packer.ts
@@ -58,11 +58,12 @@ export class PaddedDataPacker extends DataPackerAbstraction {
/** {@link DataPackerAbstraction.unpack} */
unpack(secret: string): Jsonify {
// frame size is stored before the JSON payload in base 10
- const frameBreakpoint = secret.indexOf(DATA_PACKING.divider);
- if (frameBreakpoint < 1) {
+ const frameEndIndex = secret.indexOf(DATA_PACKING.divider);
+ if (frameEndIndex < 1) {
throw new Error("missing frame size");
}
- const frameSize = parseInt(secret.slice(0, frameBreakpoint), 10);
+ const frameSize = parseInt(secret.slice(0, frameEndIndex), 10);
+ const dataStartIndex = frameEndIndex + 1;
// The decrypted string should be a multiple of the frame length
if (secret.length % frameSize > 0) {
@@ -70,20 +71,20 @@ export class PaddedDataPacker extends DataPackerAbstraction {
}
// encoded data terminates with the divider, followed by the padding character
- const jsonBreakpoint = secret.lastIndexOf(DATA_PACKING.divider);
- if (jsonBreakpoint == frameBreakpoint) {
+ const dataEndIndex = secret.lastIndexOf(DATA_PACKING.divider);
+ if (dataEndIndex == frameEndIndex) {
throw new Error("missing json object");
}
- const paddingBegins = jsonBreakpoint + 1;
+ const paddingStartIndex = dataEndIndex + 1;
// If the padding contains invalid padding characters then the padding could be used
// as a side channel for arbitrary data.
- if (secret.slice(paddingBegins).match(DATA_PACKING.hasInvalidPadding)) {
+ if (secret.slice(paddingStartIndex).match(DATA_PACKING.hasInvalidPadding)) {
throw new Error("invalid padding");
}
// remove frame size and padding
- const b64 = secret.substring(frameBreakpoint, paddingBegins);
+ const b64 = secret.slice(dataStartIndex, dataEndIndex);
// unpack the stored data
const json = Utils.fromB64ToUtf8(b64);
From 2ff990edd28ad9e6e6bc2c573fecb412033b5695 Mon Sep 17 00:00:00 2001
From: Addison Beck
Date: Fri, 5 Apr 2024 13:10:24 -0500
Subject: [PATCH 07/10] Update policy service to clear its own state (#8564)
---
.../browser/src/background/main.background.ts | 1 -
apps/cli/src/bw.ts | 1 -
apps/desktop/src/app/app.component.ts | 1 -
apps/web/src/app/app.component.ts | 1 -
.../policy/policy.service.abstraction.ts | 1 -
.../services/policy/policy.service.spec.ts | 60 -------------------
.../services/policy/policy.service.ts | 9 +--
7 files changed, 3 insertions(+), 71 deletions(-)
diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts
index 255538de52..235ccdf1aa 100644
--- a/apps/browser/src/background/main.background.ts
+++ b/apps/browser/src/background/main.background.ts
@@ -1139,7 +1139,6 @@ export default class MainBackground {
this.cipherService.clear(userId),
this.folderService.clear(userId),
this.collectionService.clear(userId),
- this.policyService.clear(userId),
this.passwordGenerationService.clear(userId),
this.vaultTimeoutSettingsService.clear(userId),
this.vaultFilterService.clear(),
diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts
index 3815fc773b..08d43a88ef 100644
--- a/apps/cli/src/bw.ts
+++ b/apps/cli/src/bw.ts
@@ -702,7 +702,6 @@ export class Main {
this.cipherService.clear(userId),
this.folderService.clear(userId),
this.collectionService.clear(userId as UserId),
- this.policyService.clear(userId as UserId),
this.passwordGenerationService.clear(),
this.providerService.save(null, userId as UserId),
]);
diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts
index 4e74135c49..71b272b897 100644
--- a/apps/desktop/src/app/app.component.ts
+++ b/apps/desktop/src/app/app.component.ts
@@ -583,7 +583,6 @@ export class AppComponent implements OnInit, OnDestroy {
await this.collectionService.clear(userBeingLoggedOut);
await this.passwordGenerationService.clear(userBeingLoggedOut);
await this.vaultTimeoutSettingsService.clear(userBeingLoggedOut);
- await this.policyService.clear(userBeingLoggedOut);
await this.biometricStateService.logout(userBeingLoggedOut as UserId);
await this.providerService.save(null, userBeingLoggedOut as UserId);
diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
index 32f4ee67e2..628875f04a 100644
--- a/apps/web/src/app/app.component.ts
+++ b/apps/web/src/app/app.component.ts
@@ -274,7 +274,6 @@ export class AppComponent implements OnDestroy, OnInit {
this.cipherService.clear(userId),
this.folderService.clear(userId),
this.collectionService.clear(userId),
- this.policyService.clear(userId),
this.passwordGenerationService.clear(),
this.biometricStateService.logout(userId as UserId),
this.paymentMethodWarningService.clear(),
diff --git a/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts b/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts
index fb805f94cd..21669f78ad 100644
--- a/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts
+++ b/libs/common/src/admin-console/abstractions/policy/policy.service.abstraction.ts
@@ -78,5 +78,4 @@ export abstract class PolicyService {
export abstract class InternalPolicyService extends PolicyService {
upsert: (policy: PolicyData) => Promise;
replace: (policies: { [id: string]: PolicyData }) => Promise;
- clear: (userId?: string) => Promise;
}
diff --git a/libs/common/src/admin-console/services/policy/policy.service.spec.ts b/libs/common/src/admin-console/services/policy/policy.service.spec.ts
index 8fa79f4d1c..a1633d29ff 100644
--- a/libs/common/src/admin-console/services/policy/policy.service.spec.ts
+++ b/libs/common/src/admin-console/services/policy/policy.service.spec.ts
@@ -102,66 +102,6 @@ describe("PolicyService", () => {
]);
});
- describe("clear", () => {
- beforeEach(() => {
- activeUserState.nextState(
- arrayToRecord([
- policyData("1", "test-organization", PolicyType.MaximumVaultTimeout, true, {
- minutes: 14,
- }),
- ]),
- );
- });
-
- it("clears state for the active user", async () => {
- await policyService.clear();
-
- expect(await firstValueFrom(policyService.policies$)).toEqual([]);
- expect(await firstValueFrom(activeUserState.state$)).toEqual(null);
- expect(stateProvider.activeUser.getFake(POLICIES).nextMock).toHaveBeenCalledWith([
- "userId",
- null,
- ]);
- });
-
- it("clears state for an inactive user", async () => {
- const inactiveUserId = "someOtherUserId" as UserId;
- const inactiveUserState = stateProvider.singleUser.getFake(inactiveUserId, POLICIES);
- inactiveUserState.nextState(
- arrayToRecord([
- policyData("10", "another-test-organization", PolicyType.PersonalOwnership, true),
- ]),
- );
-
- await policyService.clear(inactiveUserId);
-
- // Active user is not affected
- const expectedActiveUserPolicy: Partial = {
- id: "1" as PolicyId,
- organizationId: "test-organization",
- type: PolicyType.MaximumVaultTimeout,
- enabled: true,
- data: { minutes: 14 },
- };
- expect(await firstValueFrom(policyService.policies$)).toEqual([expectedActiveUserPolicy]);
- expect(await firstValueFrom(activeUserState.state$)).toEqual({
- "1": expectedActiveUserPolicy,
- });
- expect(stateProvider.activeUser.getFake(POLICIES).nextMock).not.toHaveBeenCalled();
-
- // Non-active user is cleared
- expect(
- await firstValueFrom(
- policyService.getAll$(PolicyType.PersonalOwnership, "someOtherUserId" as UserId),
- ),
- ).toEqual([]);
- expect(await firstValueFrom(inactiveUserState.state$)).toEqual(null);
- expect(
- stateProvider.singleUser.getFake("someOtherUserId" as UserId, POLICIES).nextMock,
- ).toHaveBeenCalledWith(null);
- });
- });
-
describe("masterPasswordPolicyOptions", () => {
it("returns default policy options", async () => {
const data: any = {
diff --git a/libs/common/src/admin-console/services/policy/policy.service.ts b/libs/common/src/admin-console/services/policy/policy.service.ts
index d60d2e3293..0cbc7204de 100644
--- a/libs/common/src/admin-console/services/policy/policy.service.ts
+++ b/libs/common/src/admin-console/services/policy/policy.service.ts
@@ -1,6 +1,6 @@
import { combineLatest, firstValueFrom, map, Observable, of } from "rxjs";
-import { KeyDefinition, POLICIES_DISK, StateProvider } from "../../../platform/state";
+import { UserKeyDefinition, POLICIES_DISK, StateProvider } from "../../../platform/state";
import { PolicyId, UserId } from "../../../types/guid";
import { OrganizationService } from "../../abstractions/organization/organization.service.abstraction";
import { InternalPolicyService as InternalPolicyServiceAbstraction } from "../../abstractions/policy/policy.service.abstraction";
@@ -14,8 +14,9 @@ import { ResetPasswordPolicyOptions } from "../../models/domain/reset-password-p
const policyRecordToArray = (policiesMap: { [id: string]: PolicyData }) =>
Object.values(policiesMap || {}).map((f) => new Policy(f));
-export const POLICIES = KeyDefinition.record(POLICIES_DISK, "policies", {
+export const POLICIES = UserKeyDefinition.record(POLICIES_DISK, "policies", {
deserializer: (policyData) => policyData,
+ clearOn: ["logout"],
});
export class PolicyService implements InternalPolicyServiceAbstraction {
@@ -222,10 +223,6 @@ export class PolicyService implements InternalPolicyServiceAbstraction {
await this.activeUserPolicyState.update(() => policies);
}
- async clear(userId?: UserId): Promise {
- await this.stateProvider.setUserState(POLICIES, null, userId);
- }
-
/**
* Determines whether an orgUser is exempt from a specific policy because of their role
* Generally orgUsers who can manage policies are exempt from them, but some policies are stricter
From 6df52262a94ba3c1a0e318417ede0388518244be Mon Sep 17 00:00:00 2001
From: Addison Beck
Date: Fri, 5 Apr 2024 13:10:55 -0500
Subject: [PATCH 08/10] Clear provider state on logout (#8563)
---
apps/browser/src/background/main.background.ts | 1 -
apps/cli/src/bw.ts | 1 -
apps/desktop/src/app/app.component.ts | 1 -
libs/common/src/admin-console/services/provider.service.ts | 5 +++--
4 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts
index 235ccdf1aa..31f0ae7279 100644
--- a/apps/browser/src/background/main.background.ts
+++ b/apps/browser/src/background/main.background.ts
@@ -1143,7 +1143,6 @@ export default class MainBackground {
this.vaultTimeoutSettingsService.clear(userId),
this.vaultFilterService.clear(),
this.biometricStateService.logout(userId),
- this.providerService.save(null, userId),
/* We intentionally do not clear:
* - autofillSettingsService
* - badgeSettingsService
diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts
index 08d43a88ef..0e6571f775 100644
--- a/apps/cli/src/bw.ts
+++ b/apps/cli/src/bw.ts
@@ -703,7 +703,6 @@ export class Main {
this.folderService.clear(userId),
this.collectionService.clear(userId as UserId),
this.passwordGenerationService.clear(),
- this.providerService.save(null, userId as UserId),
]);
await this.stateEventRunnerService.handleEvent("logout", userId as UserId);
diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts
index 71b272b897..884296ea29 100644
--- a/apps/desktop/src/app/app.component.ts
+++ b/apps/desktop/src/app/app.component.ts
@@ -584,7 +584,6 @@ export class AppComponent implements OnInit, OnDestroy {
await this.passwordGenerationService.clear(userBeingLoggedOut);
await this.vaultTimeoutSettingsService.clear(userBeingLoggedOut);
await this.biometricStateService.logout(userBeingLoggedOut as UserId);
- await this.providerService.save(null, userBeingLoggedOut as UserId);
await this.stateEventRunnerService.handleEvent("logout", userBeingLoggedOut as UserId);
diff --git a/libs/common/src/admin-console/services/provider.service.ts b/libs/common/src/admin-console/services/provider.service.ts
index 47291a5520..064e0c7175 100644
--- a/libs/common/src/admin-console/services/provider.service.ts
+++ b/libs/common/src/admin-console/services/provider.service.ts
@@ -1,13 +1,14 @@
import { Observable, map, firstValueFrom, of, switchMap, take } from "rxjs";
-import { KeyDefinition, PROVIDERS_DISK, StateProvider } from "../../platform/state";
+import { UserKeyDefinition, PROVIDERS_DISK, StateProvider } from "../../platform/state";
import { UserId } from "../../types/guid";
import { ProviderService as ProviderServiceAbstraction } from "../abstractions/provider.service";
import { ProviderData } from "../models/data/provider.data";
import { Provider } from "../models/domain/provider";
-export const PROVIDERS = KeyDefinition.record(PROVIDERS_DISK, "providers", {
+export const PROVIDERS = UserKeyDefinition.record(PROVIDERS_DISK, "providers", {
deserializer: (obj: ProviderData) => obj,
+ clearOn: ["logout"],
});
function mapToSingleProvider(providerId: string) {
From 8ae44b13ed4931fa4445a66acbf2d29be8933c9b Mon Sep 17 00:00:00 2001
From: Cesar Gonzalez
Date: Fri, 5 Apr 2024 16:33:03 -0500
Subject: [PATCH 09/10] [CL-255] Opening a menu by mouse click shows an outline
on the first submenu item (#8629)
---
libs/components/src/menu/menu-item.directive.ts | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libs/components/src/menu/menu-item.directive.ts b/libs/components/src/menu/menu-item.directive.ts
index 2a50dd366f..77246bbcdf 100644
--- a/libs/components/src/menu/menu-item.directive.ts
+++ b/libs/components/src/menu/menu-item.directive.ts
@@ -16,12 +16,12 @@ export class MenuItemDirective implements FocusableOption {
"tw-bg-background",
"tw-text-left",
"hover:tw-bg-secondary-100",
- "focus:tw-bg-secondary-100",
- "focus:tw-z-50",
- "focus:tw-outline-none",
- "focus:tw-ring",
- "focus:tw-ring-offset-2",
- "focus:tw-ring-primary-700",
+ "focus-visible:tw-bg-secondary-100",
+ "focus-visible:tw-z-50",
+ "focus-visible:tw-outline-none",
+ "focus-visible:tw-ring",
+ "focus-visible:tw-ring-offset-2",
+ "focus-visible:tw-ring-primary-700",
"active:!tw-ring-0",
"active:!tw-ring-offset-0",
];
From 216bbdb44c0d4e5f2977017518d37144a9750d12 Mon Sep 17 00:00:00 2001
From: Jonathan Prusik
Date: Fri, 5 Apr 2024 17:36:52 -0400
Subject: [PATCH 10/10] fix notification bar content script using old server
config state storage (#8618)
---
.../abstractions/notification.background.ts | 2 ++
.../notification.background.spec.ts | 3 ++
.../background/notification.background.ts | 11 ++++++++
.../src/autofill/content/notification-bar.ts | 28 ++++++-------------
.../browser/src/background/main.background.ts | 1 +
5 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/apps/browser/src/autofill/background/abstractions/notification.background.ts b/apps/browser/src/autofill/background/abstractions/notification.background.ts
index ac40bb315b..e01e2c5c02 100644
--- a/apps/browser/src/autofill/background/abstractions/notification.background.ts
+++ b/apps/browser/src/autofill/background/abstractions/notification.background.ts
@@ -1,4 +1,5 @@
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
+import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { NotificationQueueMessageTypes } from "../../enums/notification-queue-message-type.enum";
@@ -113,6 +114,7 @@ type NotificationBackgroundExtensionMessageHandlers = {
bgGetEnableChangedPasswordPrompt: () => Promise;
bgGetEnableAddedLoginPrompt: () => Promise;
bgGetExcludedDomains: () => Promise;
+ bgGetActiveUserServerConfig: () => Promise;
getWebVaultUrlForNotification: () => Promise;
};
diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts
index 3b05cf57a9..fd15ea6e93 100644
--- a/apps/browser/src/autofill/background/notification.background.spec.ts
+++ b/apps/browser/src/autofill/background/notification.background.spec.ts
@@ -6,6 +6,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
@@ -54,6 +55,7 @@ describe("NotificationBackground", () => {
const environmentService = mock();
const logService = mock();
const themeStateService = mock();
+ const configService = mock();
beforeEach(() => {
notificationBackground = new NotificationBackground(
@@ -68,6 +70,7 @@ describe("NotificationBackground", () => {
environmentService,
logService,
themeStateService,
+ configService,
);
});
diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts
index c14531ee74..74e6147505 100644
--- a/apps/browser/src/autofill/background/notification.background.ts
+++ b/apps/browser/src/autofill/background/notification.background.ts
@@ -8,6 +8,8 @@ import { NOTIFICATION_BAR_LIFESPAN_MS } from "@bitwarden/common/autofill/constan
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
+import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
+import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@@ -64,6 +66,7 @@ export default class NotificationBackground {
bgGetEnableChangedPasswordPrompt: () => this.getEnableChangedPasswordPrompt(),
bgGetEnableAddedLoginPrompt: () => this.getEnableAddedLoginPrompt(),
bgGetExcludedDomains: () => this.getExcludedDomains(),
+ bgGetActiveUserServerConfig: () => this.getActiveUserServerConfig(),
getWebVaultUrlForNotification: () => this.getWebVaultUrl(),
};
@@ -79,6 +82,7 @@ export default class NotificationBackground {
private environmentService: EnvironmentService,
private logService: LogService,
private themeStateService: ThemeStateService,
+ private configService: ConfigService,
) {}
async init() {
@@ -112,6 +116,13 @@ export default class NotificationBackground {
return await firstValueFrom(this.domainSettingsService.neverDomains$);
}
+ /**
+ * Gets the active user server config from the config service.
+ */
+ async getActiveUserServerConfig(): Promise {
+ return await firstValueFrom(this.configService.serverConfig$);
+ }
+
/**
* Checks the notification queue for any messages that need to be sent to the
* specified tab. If no tab is specified, the current tab will be used.
diff --git a/apps/browser/src/autofill/content/notification-bar.ts b/apps/browser/src/autofill/content/notification-bar.ts
index 8c1ef93c32..2bcf4394fd 100644
--- a/apps/browser/src/autofill/content/notification-bar.ts
+++ b/apps/browser/src/autofill/content/notification-bar.ts
@@ -1,3 +1,4 @@
+import { ServerConfig } from "../../../../../libs/common/src/platform/abstractions/config/server-config";
import {
AddLoginMessageData,
ChangePasswordMessageData,
@@ -6,12 +7,7 @@ import AutofillField from "../models/autofill-field";
import { WatchedForm } from "../models/watched-form";
import { NotificationBarIframeInitData } from "../notification/abstractions/notification-bar";
import { FormData } from "../services/abstractions/autofill.service";
-import { UserSettings } from "../types";
-import {
- getFromLocalStorage,
- sendExtensionMessage,
- setupExtensionDisconnectAction,
-} from "../utils";
+import { sendExtensionMessage, setupExtensionDisconnectAction } from "../utils";
interface HTMLElementWithFormOpId extends HTMLElement {
formOpId: string;
@@ -95,25 +91,17 @@ async function loadNotificationBar() {
);
const enableAddedLoginPrompt = await sendExtensionMessage("bgGetEnableAddedLoginPrompt");
const excludedDomains = await sendExtensionMessage("bgGetExcludedDomains");
+ const activeUserServerConfig: ServerConfig = await sendExtensionMessage(
+ "bgGetActiveUserServerConfig",
+ );
+ const activeUserVault = activeUserServerConfig?.environment?.vault;
let showNotificationBar = true;
- // Look up the active user id from storage
- const activeUserIdKey = "activeUserId";
- let activeUserId: string;
-
- const activeUserStorageValue = await getFromLocalStorage(activeUserIdKey);
- if (activeUserStorageValue[activeUserIdKey]) {
- activeUserId = activeUserStorageValue[activeUserIdKey];
- }
-
- // Look up the user's settings from storage
- const userSettingsStorageValue = await getFromLocalStorage(activeUserId);
- if (userSettingsStorageValue[activeUserId]) {
- const userSettings: UserSettings = userSettingsStorageValue[activeUserId].settings;
+ if (activeUserVault) {
// Do not show the notification bar on the Bitwarden vault
// because they can add logins and change passwords there
- if (window.location.origin === userSettings.serverConfig.environment.vault) {
+ if (window.location.origin === activeUserVault) {
showNotificationBar = false;
} else {
// NeverDomains is a dictionary of domains that the user has chosen to never
diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts
index 31f0ae7279..f8a8e4fdb9 100644
--- a/apps/browser/src/background/main.background.ts
+++ b/apps/browser/src/background/main.background.ts
@@ -908,6 +908,7 @@ export default class MainBackground {
this.environmentService,
this.logService,
themeStateService,
+ this.configService,
);
this.overlayBackground = new OverlayBackground(
this.cipherService,