From c73372310b7688881d4cc521d705df58f4e7a3e3 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Mon, 8 Apr 2024 14:32:14 -0500 Subject: [PATCH 01/27] fix: remove TXT generation, separate save/verify steps, refs AC-2350 (#8540) --- .../domain-add-edit-dialog.component.html | 9 ++++++--- .../domain-add-edit-dialog.component.ts | 17 +++-------------- .../requests/organization-domain.request.ts | 4 +--- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html index fcbfcb74e6a..0d0ca04f926 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html @@ -26,7 +26,7 @@ {{ "domainNameInputHint" | i18n }} - + {{ "dnsTxtRecord" | i18n }} {{ "dnsTxtRecordInputHint" | i18n }} @@ -42,7 +42,7 @@ @@ -51,7 +51,10 @@ -

diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index dd1b6790dee..6389be48c31 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -3,11 +3,14 @@ import { Router } from "@angular/router"; import { Subject, firstValueFrom, from } from "rxjs"; import { debounceTime, switchMap, takeUntil } from "rxjs/operators"; +import { UnassignedItemsBannerService } from "@bitwarden/angular/services/unassigned-items-banner.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -54,6 +57,10 @@ export class CurrentTabComponent implements OnInit, OnDestroy { private loadedTimeout: number; private searchTimeout: number; + protected unassignedItemsBannerEnabled$ = this.configService.getFeatureFlag$( + FeatureFlag.UnassignedItemsBanner, + ); + constructor( private platformUtilsService: PlatformUtilsService, private cipherService: CipherService, @@ -70,6 +77,8 @@ export class CurrentTabComponent implements OnInit, OnDestroy { private organizationService: OrganizationService, private vaultFilterService: VaultFilterService, private vaultSettingsService: VaultSettingsService, + private configService: ConfigService, + protected unassignedItemsBannerService: UnassignedItemsBannerService, ) {} async ngOnInit() { diff --git a/libs/angular/src/services/unassigned-items-banner.service.spec.ts b/libs/angular/src/services/unassigned-items-banner.service.spec.ts new file mode 100644 index 00000000000..eedfbf3429f --- /dev/null +++ b/libs/angular/src/services/unassigned-items-banner.service.spec.ts @@ -0,0 +1,53 @@ +import { MockProxy, mock } from "jest-mock-extended"; +import { firstValueFrom, skip } from "rxjs"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; + +import { SHOW_BANNER_KEY, UnassignedItemsBannerService } from "./unassigned-items-banner.service"; + +describe("UnassignedItemsBanner", () => { + let stateProvider: FakeStateProvider; + let apiService: MockProxy; + + const sutFactory = () => new UnassignedItemsBannerService(stateProvider, apiService); + + beforeEach(() => { + const fakeAccountService = mockAccountServiceWith("userId" as UserId); + stateProvider = new FakeStateProvider(fakeAccountService); + apiService = mock(); + }); + + it("shows the banner if showBanner local state is true", async () => { + const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); + showBanner.nextState(true); + + const sut = sutFactory(); + expect(await firstValueFrom(sut.showBanner$)).toBe(true); + expect(apiService.getShowUnassignedCiphersBanner).not.toHaveBeenCalled(); + }); + + it("does not show the banner if showBanner local state is false", async () => { + const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); + showBanner.nextState(false); + + const sut = sutFactory(); + expect(await firstValueFrom(sut.showBanner$)).toBe(false); + expect(apiService.getShowUnassignedCiphersBanner).not.toHaveBeenCalled(); + }); + + it("fetches from server if local state has not been set yet", async () => { + apiService.getShowUnassignedCiphersBanner.mockResolvedValue(true); + + const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); + showBanner.nextState(undefined); + + const sut = sutFactory(); + // skip first value so we get the recomputed value after the server call + expect(await firstValueFrom(sut.showBanner$.pipe(skip(1)))).toBe(true); + // Expect to have updated local state + expect(await firstValueFrom(showBanner.state$)).toBe(true); + expect(apiService.getShowUnassignedCiphersBanner).toHaveBeenCalledTimes(1); + }); +}); diff --git a/libs/angular/src/services/unassigned-items-banner.service.ts b/libs/angular/src/services/unassigned-items-banner.service.ts new file mode 100644 index 00000000000..dd374fe5cef --- /dev/null +++ b/libs/angular/src/services/unassigned-items-banner.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from "@angular/core"; +import { EMPTY, concatMap } from "rxjs"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { + StateProvider, + UNASSIGNED_ITEMS_BANNER_DISK, + UserKeyDefinition, +} from "@bitwarden/common/platform/state"; + +export const SHOW_BANNER_KEY = new UserKeyDefinition( + UNASSIGNED_ITEMS_BANNER_DISK, + "showBanner", + { + deserializer: (b) => b, + clearOn: [], + }, +); + +/** Displays a banner that tells users how to move their unassigned items into a collection. */ +@Injectable({ providedIn: "root" }) +export class UnassignedItemsBannerService { + private _showBanner = this.stateProvider.getActive(SHOW_BANNER_KEY); + + showBanner$ = this._showBanner.state$.pipe( + concatMap(async (showBanner) => { + // null indicates that the user has not seen or dismissed the banner yet - get the flag from server + if (showBanner == null) { + const showBannerResponse = await this.apiService.getShowUnassignedCiphersBanner(); + await this._showBanner.update(() => showBannerResponse); + return EMPTY; // complete the inner observable without emitting any value; the update on the previous line will trigger another run + } + + return showBanner; + }), + ); + + constructor( + private stateProvider: StateProvider, + private apiService: ApiService, + ) {} + + async hideBanner() { + await this._showBanner.update(() => false); + } +} From ab83a367dd5e0cdcca73f8881b305ea4cb484985 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Wed, 10 Apr 2024 16:13:41 -0500 Subject: [PATCH 21/27] Address review feedback on `UnassignedBannerService` (#8680) * Introduce `UnassignedItemsBannerApiService` * Delete `WebUnassignedItemsBannerService` --- .../layouts/header/web-header.component.html | 4 +- .../layouts/header/web-header.component.ts | 5 +- ...eb-unassigned-items-banner.service.spec.ts | 56 ------------------- .../web-unassigned-items-banner.service.ts | 46 --------------- .../unassigned-items-banner.api.service.ts | 19 +++++++ .../unassigned-items-banner.service.spec.ts | 4 +- .../unassigned-items-banner.service.ts | 5 +- libs/common/src/abstractions/api.service.ts | 1 - libs/common/src/services/api.service.ts | 5 -- 9 files changed, 28 insertions(+), 117 deletions(-) delete mode 100644 apps/web/src/app/layouts/header/web-unassigned-items-banner.service.spec.ts delete mode 100644 apps/web/src/app/layouts/header/web-unassigned-items-banner.service.ts create mode 100644 libs/angular/src/services/unassigned-items-banner.api.service.ts diff --git a/apps/web/src/app/layouts/header/web-header.component.html b/apps/web/src/app/layouts/header/web-header.component.html index 1555726e2b6..e1cda607c01 100644 --- a/apps/web/src/app/layouts/header/web-header.component.html +++ b/apps/web/src/app/layouts/header/web-header.component.html @@ -1,8 +1,8 @@ {{ "unassignedItemsBanner" | i18n }} diff --git a/apps/web/src/app/layouts/header/web-header.component.ts b/apps/web/src/app/layouts/header/web-header.component.ts index 6016463ebbf..1f012e52ddc 100644 --- a/apps/web/src/app/layouts/header/web-header.component.ts +++ b/apps/web/src/app/layouts/header/web-header.component.ts @@ -2,6 +2,7 @@ import { Component, Input } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { combineLatest, map, Observable } from "rxjs"; +import { UnassignedItemsBannerService } from "@bitwarden/angular/services/unassigned-items-banner.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; @@ -11,8 +12,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { AccountProfile } from "@bitwarden/common/platform/models/domain/account"; -import { WebUnassignedItemsBannerService } from "./web-unassigned-items-banner.service"; - @Component({ selector: "app-header", templateUrl: "./web-header.component.html", @@ -43,7 +42,7 @@ export class WebHeaderComponent { private platformUtilsService: PlatformUtilsService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService, private messagingService: MessagingService, - protected webUnassignedItemsBannerService: WebUnassignedItemsBannerService, + protected unassignedItemsBannerService: UnassignedItemsBannerService, private configService: ConfigService, ) { this.routeData$ = this.route.data.pipe( diff --git a/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.spec.ts b/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.spec.ts deleted file mode 100644 index a9db11a2013..00000000000 --- a/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { MockProxy, mock } from "jest-mock-extended"; -import { firstValueFrom, skip } from "rxjs"; - -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; -import { UserId } from "@bitwarden/common/types/guid"; - -import { - SHOW_BANNER_KEY, - WebUnassignedItemsBannerService, -} from "./web-unassigned-items-banner.service"; - -describe("WebUnassignedItemsBanner", () => { - let stateProvider: FakeStateProvider; - let apiService: MockProxy; - - const sutFactory = () => new WebUnassignedItemsBannerService(stateProvider, apiService); - - beforeEach(() => { - const fakeAccountService = mockAccountServiceWith("userId" as UserId); - stateProvider = new FakeStateProvider(fakeAccountService); - apiService = mock(); - }); - - it("shows the banner if showBanner local state is true", async () => { - const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); - showBanner.nextState(true); - - const sut = sutFactory(); - expect(await firstValueFrom(sut.showBanner$)).toBe(true); - expect(apiService.getShowUnassignedCiphersBanner).not.toHaveBeenCalled(); - }); - - it("does not show the banner if showBanner local state is false", async () => { - const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); - showBanner.nextState(false); - - const sut = sutFactory(); - expect(await firstValueFrom(sut.showBanner$)).toBe(false); - expect(apiService.getShowUnassignedCiphersBanner).not.toHaveBeenCalled(); - }); - - it("fetches from server if local state has not been set yet", async () => { - apiService.getShowUnassignedCiphersBanner.mockResolvedValue(true); - - const showBanner = stateProvider.activeUser.getFake(SHOW_BANNER_KEY); - showBanner.nextState(undefined); - - const sut = sutFactory(); - // skip first value so we get the recomputed value after the server call - expect(await firstValueFrom(sut.showBanner$.pipe(skip(1)))).toBe(true); - // Expect to have updated local state - expect(await firstValueFrom(showBanner.state$)).toBe(true); - expect(apiService.getShowUnassignedCiphersBanner).toHaveBeenCalledTimes(1); - }); -}); diff --git a/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.ts b/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.ts deleted file mode 100644 index 8f09b685479..00000000000 --- a/apps/web/src/app/layouts/header/web-unassigned-items-banner.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Injectable } from "@angular/core"; -import { EMPTY, concatMap } from "rxjs"; - -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { - StateProvider, - UNASSIGNED_ITEMS_BANNER_DISK, - UserKeyDefinition, -} from "@bitwarden/common/platform/state"; - -export const SHOW_BANNER_KEY = new UserKeyDefinition( - UNASSIGNED_ITEMS_BANNER_DISK, - "showBanner", - { - deserializer: (b) => b, - clearOn: [], - }, -); - -/** Displays a banner that tells users how to move their unassigned items into a collection. */ -@Injectable({ providedIn: "root" }) -export class WebUnassignedItemsBannerService { - private _showBanner = this.stateProvider.getActive(SHOW_BANNER_KEY); - - showBanner$ = this._showBanner.state$.pipe( - concatMap(async (showBanner) => { - // null indicates that the user has not seen or dismissed the banner yet - get the flag from server - if (showBanner == null) { - const showBannerResponse = await this.apiService.getShowUnassignedCiphersBanner(); - await this._showBanner.update(() => showBannerResponse); - return EMPTY; // complete the inner observable without emitting any value; the update on the previous line will trigger another run - } - - return showBanner; - }), - ); - - constructor( - private stateProvider: StateProvider, - private apiService: ApiService, - ) {} - - async hideBanner() { - await this._showBanner.update(() => false); - } -} diff --git a/libs/angular/src/services/unassigned-items-banner.api.service.ts b/libs/angular/src/services/unassigned-items-banner.api.service.ts new file mode 100644 index 00000000000..69b74f8c7fa --- /dev/null +++ b/libs/angular/src/services/unassigned-items-banner.api.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from "@angular/core"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; + +@Injectable({ providedIn: "root" }) +export class UnassignedItemsBannerApiService { + constructor(private apiService: ApiService) {} + + async getShowUnassignedCiphersBanner(): Promise { + const r = await this.apiService.send( + "GET", + "/ciphers/has-unassigned-ciphers", + null, + true, + true, + ); + return r; + } +} diff --git a/libs/angular/src/services/unassigned-items-banner.service.spec.ts b/libs/angular/src/services/unassigned-items-banner.service.spec.ts index eedfbf3429f..ac80f7d651a 100644 --- a/libs/angular/src/services/unassigned-items-banner.service.spec.ts +++ b/libs/angular/src/services/unassigned-items-banner.service.spec.ts @@ -1,15 +1,15 @@ import { MockProxy, mock } from "jest-mock-extended"; import { firstValueFrom, skip } from "rxjs"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; +import { UnassignedItemsBannerApiService } from "./unassigned-items-banner.api.service"; import { SHOW_BANNER_KEY, UnassignedItemsBannerService } from "./unassigned-items-banner.service"; describe("UnassignedItemsBanner", () => { let stateProvider: FakeStateProvider; - let apiService: MockProxy; + let apiService: MockProxy; const sutFactory = () => new UnassignedItemsBannerService(stateProvider, apiService); diff --git a/libs/angular/src/services/unassigned-items-banner.service.ts b/libs/angular/src/services/unassigned-items-banner.service.ts index dd374fe5cef..bc567aa44ea 100644 --- a/libs/angular/src/services/unassigned-items-banner.service.ts +++ b/libs/angular/src/services/unassigned-items-banner.service.ts @@ -1,13 +1,14 @@ import { Injectable } from "@angular/core"; import { EMPTY, concatMap } from "rxjs"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { StateProvider, UNASSIGNED_ITEMS_BANNER_DISK, UserKeyDefinition, } from "@bitwarden/common/platform/state"; +import { UnassignedItemsBannerApiService } from "./unassigned-items-banner.api.service"; + export const SHOW_BANNER_KEY = new UserKeyDefinition( UNASSIGNED_ITEMS_BANNER_DISK, "showBanner", @@ -37,7 +38,7 @@ export class UnassignedItemsBannerService { constructor( private stateProvider: StateProvider, - private apiService: ApiService, + private apiService: UnassignedItemsBannerApiService, ) {} async hideBanner() { diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 811cca8638f..20ed3216a54 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -207,7 +207,6 @@ export abstract class ApiService { emergencyAccessId?: string, ) => Promise; getCiphersOrganization: (organizationId: string) => Promise>; - getShowUnassignedCiphersBanner: () => Promise; postCipher: (request: CipherRequest) => Promise; postCipherCreate: (request: CipherCreateRequest) => Promise; postCipherAdmin: (request: CipherCreateRequest) => Promise; diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 501b924e5b9..6306eb1e288 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -506,11 +506,6 @@ export class ApiService implements ApiServiceAbstraction { return new ListResponse(r, CipherResponse); } - async getShowUnassignedCiphersBanner(): Promise { - const r = await this.send("GET", "/ciphers/has-unassigned-ciphers", null, true, true); - return r; - } - async postCipher(request: CipherRequest): Promise { const r = await this.send("POST", "/ciphers", request, true, true); return new CipherResponse(r); From 83fef10c4c7f8861a93570e7bfbb4ad27118696a Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:31:20 -0400 Subject: [PATCH 22/27] Bumped desktop version to (#8683) --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 52dd0fafdb2..842bc0015ca 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2024.3.2", + "version": "2024.4.0", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 167c32cc81d..15a681a5641 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.3.2", + "version": "2024.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.3.2", + "version": "2024.4.0", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-native": "file:../desktop_native", diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index cfc0b9b4e2b..5e574bd6d51 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2024.3.2", + "version": "2024.4.0", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index d19f27e5350..7ef7b7f0704 100644 --- a/package-lock.json +++ b/package-lock.json @@ -233,7 +233,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.3.2", + "version": "2024.4.0", "hasInstallScript": true, "license": "GPL-3.0" }, From 4607ae73c0a2a9606d895f2c4173fa649e5ba13e Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:45:31 -0400 Subject: [PATCH 23/27] Bumped browser,desktop version to (#8684) --- apps/browser/package.json | 2 +- apps/browser/src/manifest.json | 2 +- apps/browser/src/manifest.v3.json | 2 +- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/browser/package.json b/apps/browser/package.json index d06eadf58d4..ee6d100572d 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2024.3.1", + "version": "2024.4.1", "scripts": { "build": "webpack", "build:mv3": "cross-env MANIFEST_VERSION=3 webpack", diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 271b2c76a2d..aec7523d5eb 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.3.1", + "version": "2024.4.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index e7b0c0cd1e7..d67b4affaba 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.3.1", + "version": "2024.4.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 842bc0015ca..0dc23b04b11 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2024.4.0", + "version": "2024.4.1", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 15a681a5641..05313451314 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.4.0", + "version": "2024.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.4.0", + "version": "2024.4.1", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-native": "file:../desktop_native", diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 5e574bd6d51..6527c215212 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2024.4.0", + "version": "2024.4.1", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index 7ef7b7f0704..c399536cca1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -193,7 +193,7 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2024.3.1" + "version": "2024.4.1" }, "apps/cli": { "name": "@bitwarden/cli", @@ -233,7 +233,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.4.0", + "version": "2024.4.1", "hasInstallScript": true, "license": "GPL-3.0" }, From e4720de62a3f727f85aaaedf3b3d18c42cf3e3c3 Mon Sep 17 00:00:00 2001 From: Cesar Gonzalez Date: Wed, 10 Apr 2024 17:06:34 -0500 Subject: [PATCH 24/27] [PM-7353] Autofill item selection not working from within current tab view in vault (#8670) * [PM-7353] Fix autofill not working from current tab component * [PM-7353] Fix autofill not working from current tab component * [PM-7353] Fix autofill not working from current tab component --- .../components/vault/current-tab.component.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index 6389be48c31..4d2674fd703 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -56,6 +56,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy { private totpTimeout: number; private loadedTimeout: number; private searchTimeout: number; + private initPageDetailsTimeout: number; protected unassignedItemsBannerEnabled$ = this.configService.getFeatureFlag$( FeatureFlag.UnassignedItemsBanner, @@ -316,18 +317,13 @@ export class CurrentTabComponent implements OnInit, OnDestroy { }); if (this.loginCiphers.length) { - void BrowserApi.tabSendMessage(this.tab, { - command: "collectPageDetails", - tab: this.tab, - sender: BroadcasterSubscriptionId, - }); - this.loginCiphers = this.loginCiphers.sort((a, b) => this.cipherService.sortCiphersByLastUsedThenName(a, b), ); } this.isLoading = this.loaded = true; + this.collectTabPageDetails(); } async goToSettings() { @@ -365,4 +361,19 @@ export class CurrentTabComponent implements OnInit, OnDestroy { this.autofillCalloutText = this.i18nService.t("autofillSelectInfoWithoutCommand"); } } + + private collectTabPageDetails() { + void BrowserApi.tabSendMessage(this.tab, { + command: "collectPageDetails", + tab: this.tab, + sender: BroadcasterSubscriptionId, + }); + + window.clearTimeout(this.initPageDetailsTimeout); + this.initPageDetailsTimeout = window.setTimeout(() => { + if (this.pageDetails.length === 0) { + this.collectTabPageDetails(); + } + }, 250); + } } From 16c289d680833cd9417209c4108d5d880b7e5407 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:55:20 -0500 Subject: [PATCH 25/27] Prefer Passed In UserId (#8602) --- apps/browser/src/background/main.background.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 1b9364556e6..bbcb9f96287 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -1188,7 +1188,7 @@ export default class MainBackground { await this.searchService.clearIndex(); } - await this.stateEventRunnerService.handleEvent("logout", currentUserId as UserId); + await this.stateEventRunnerService.handleEvent("logout", userId); if (newActiveUser != null) { // we have a new active user, do not continue tearing down application From 9b022d2fc0b86eb058ea037bcde2faf7c1b15224 Mon Sep 17 00:00:00 2001 From: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Date: Wed, 10 Apr 2024 17:40:53 -0700 Subject: [PATCH 26/27] Decrease snap description character length to reach 128 limit (#8687) --- apps/desktop/electron-builder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 81e88abca87..5fd26f32bab 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -228,7 +228,7 @@ "artifactName": "${productName}-${version}-${arch}.${ext}" }, "snap": { - "summary": "**Installation**\nBitwarden requires access to the `password-manager-service`. Please enable it through permissions or by running `sudo snap connect bitwarden:password-manager-service` after installation.", + "summary": "After installation enable required `password-manager-service` by running `sudo snap connect bitwarden:password-manager-service`.", "autoStart": true, "base": "core22", "confinement": "strict", From b843aa6bd1d188b8c1ce450249df22f562721224 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Thu, 11 Apr 2024 21:32:44 +1000 Subject: [PATCH 27/27] [AC-2436] Fix flashing unassigned items banner (#8689) * Fix flashing banner for users who shouldn't see it * Emit the right value the first time * simplify further * restore comment --- .../services/unassigned-items-banner.service.spec.ts | 8 +++----- .../src/services/unassigned-items-banner.service.ts | 10 +++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libs/angular/src/services/unassigned-items-banner.service.spec.ts b/libs/angular/src/services/unassigned-items-banner.service.spec.ts index ac80f7d651a..9b2ffc1ef9c 100644 --- a/libs/angular/src/services/unassigned-items-banner.service.spec.ts +++ b/libs/angular/src/services/unassigned-items-banner.service.spec.ts @@ -1,5 +1,5 @@ import { MockProxy, mock } from "jest-mock-extended"; -import { firstValueFrom, skip } from "rxjs"; +import { firstValueFrom } from "rxjs"; import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; @@ -44,10 +44,8 @@ describe("UnassignedItemsBanner", () => { showBanner.nextState(undefined); const sut = sutFactory(); - // skip first value so we get the recomputed value after the server call - expect(await firstValueFrom(sut.showBanner$.pipe(skip(1)))).toBe(true); - // Expect to have updated local state - expect(await firstValueFrom(showBanner.state$)).toBe(true); + + expect(await firstValueFrom(sut.showBanner$)).toBe(true); expect(apiService.getShowUnassignedCiphersBanner).toHaveBeenCalledTimes(1); }); }); diff --git a/libs/angular/src/services/unassigned-items-banner.service.ts b/libs/angular/src/services/unassigned-items-banner.service.ts index bc567aa44ea..faa766a18a8 100644 --- a/libs/angular/src/services/unassigned-items-banner.service.ts +++ b/libs/angular/src/services/unassigned-items-banner.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { EMPTY, concatMap } from "rxjs"; +import { concatMap } from "rxjs"; import { StateProvider, @@ -24,15 +24,15 @@ export class UnassignedItemsBannerService { private _showBanner = this.stateProvider.getActive(SHOW_BANNER_KEY); showBanner$ = this._showBanner.state$.pipe( - concatMap(async (showBanner) => { + concatMap(async (showBannerState) => { // null indicates that the user has not seen or dismissed the banner yet - get the flag from server - if (showBanner == null) { + if (showBannerState == null) { const showBannerResponse = await this.apiService.getShowUnassignedCiphersBanner(); await this._showBanner.update(() => showBannerResponse); - return EMPTY; // complete the inner observable without emitting any value; the update on the previous line will trigger another run + return showBannerResponse; } - return showBanner; + return showBannerState; }), );