diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index e91fba2e87a..a0d9026e471 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -42,10 +42,11 @@ on: env: _AZ_REGISTRY: bitwardenprod.azurecr.io + jobs: setup: name: Setup - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: version: ${{ steps.version.outputs.value }} node_version: ${{ steps.retrieve-node-version.outputs.node_version }} @@ -54,7 +55,7 @@ jobs: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha }} - name: Get GitHub sha as version id: version @@ -75,133 +76,61 @@ jobs: has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT - build-artifacts: - name: Build artifacts - runs-on: ubuntu-22.04 - needs: - - setup - env: - _VERSION: ${{ needs.setup.outputs.version }} - _NODE_VERSION: ${{ needs.setup.outputs.node_version }} - strategy: - matrix: - include: - - name: "selfhosted-open-source" - npm_command: "dist:oss:selfhost" - - name: "cloud-COMMERCIAL" - npm_command: "dist:bit:cloud" - - name: "selfhosted-COMMERCIAL" - npm_command: "dist:bit:selfhost" - - name: "cloud-QA" - npm_command: "build:bit:qa" - git_metadata: true - - name: "ee" - npm_command: "build:bit:ee" - git_metadata: true - - name: "cloud-euprd" - npm_command: "build:bit:euprd" - - name: "cloud-euqa" - npm_command: "build:bit:euqa" - git_metadata: true - - name: "cloud-usdev" - npm_command: "build:bit:usdev" - git_metadata: true - - steps: - - name: Check out repo - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Set up Node - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 - with: - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - node-version: ${{ env._NODE_VERSION }} - - - name: Print environment - run: | - whoami - node --version - npm --version - docker --version - echo "GitHub ref: $GITHUB_REF" - echo "GitHub event: $GITHUB_EVENT" - - - name: Install dependencies - run: npm ci - - - name: Download SDK Artifacts - if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }} - uses: bitwarden/gh-actions/download-artifacts@main - with: - github_token: ${{secrets.GITHUB_TOKEN}} - workflow: build-wasm-internal.yml - workflow_conclusion: success - branch: ${{ inputs.sdk_branch }} - artifacts: sdk-internal - repo: bitwarden/sdk-internal - path: ../sdk-internal - if_no_artifact_found: fail - - - name: Override SDK - if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }} - working-directory: ./ - run: | - ls -l ../ - npm link ../sdk-internal - - - name: Add Git metadata to build version - working-directory: apps/web - if: matrix.git_metadata - run: | - VERSION=$( jq -r ".version" package.json) - jq --arg version "$VERSION+${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp - mv package.json.tmp package.json - - - name: Build ${{ matrix.name }} - working-directory: apps/web - run: npm run ${{ matrix.npm_command }} - - - name: Package artifact - working-directory: apps/web - run: zip -r web-${{ env._VERSION }}-${{ matrix.name }}.zip build - - - name: Upload ${{ matrix.name }} artifact - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 - with: - name: web-${{ env._VERSION }}-${{ matrix.name }}.zip - path: apps/web/web-${{ env._VERSION }}-${{ matrix.name }}.zip - if-no-files-found: error - build-containers: - name: Build Docker images - runs-on: ubuntu-22.04 + name: Build artifacts and container images + runs-on: ubuntu-24.04 permissions: security-events: write id-token: write - needs: - - setup - - build-artifacts + needs: setup strategy: fail-fast: false matrix: include: - - artifact_name: cloud-QA - image_name: web-qa-cloud - - artifact_name: ee - image_name: web-ee + - artifact_name: selfhosted-open-source + image_name: web-oss + npm_command: dist:oss:selfhost + - artifact_name: cloud-COMMERCIAL + image_name: web-cloud + npm_command: dist:bit:cloud - artifact_name: selfhosted-COMMERCIAL image_name: web + npm_command: dist:bit:selfhost + - artifact_name: cloud-QA + image_name: web-qa-cloud + npm_command: build:bit:qa + git_metadata: true + - artifact_name: ee + image_name: web-ee + npm_command: build:bit:ee + git_metadata: true + - artifact_name: cloud-euprd + image_name: web-euprd + npm_command: build:bit:euprd + - artifact_name: cloud-euqa + image_name: web-euqa + npm_command: build:bit:euqa + git_metadata: true + - artifact_name: cloud-usdev + image_name: web-usdev + npm_command: build:bit:usdev + git_metadata: true env: + _NODE_VERSION: ${{ needs.setup.outputs.node_version }} _VERSION: ${{ needs.setup.outputs.version }} steps: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha }} + + - name: Check out Server repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + path: server + repository: bitwarden/server + ref: ${{ github.event.pull_request.head.sha && 'main' || github.ref }} - name: Check Branch to Publish env: @@ -216,6 +145,21 @@ jobs: echo "is_publish_branch=false" >> $GITHUB_ENV fi + - name: Add Git metadata to build version + working-directory: apps/web + if: matrix.git_metadata + run: | + VERSION=$( jq -r ".version" package.json) + jq --arg version "$VERSION+${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp + mv package.json.tmp package.json + + ########## Set up Docker ########## + - name: Set up QEMU emulators + uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + ########## ACRs ########## - name: Login to Prod Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} @@ -225,7 +169,7 @@ jobs: - name: Log into Prod container registry if: ${{ needs.setup.outputs.has_secrets == 'true' }} - run: az acr login -n bitwardenprod + run: az acr login -n ${_AZ_REGISTRY%.azurecr.io} - name: Login to Azure - CI Subscription if: ${{ needs.setup.outputs.has_secrets == 'true' }} @@ -241,14 +185,8 @@ jobs: keyvault: "bitwarden-ci" secrets: "github-pat-bitwarden-devops-bot-repo-scope" - - name: Download ${{ matrix.artifact_name }} artifact - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - with: - name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip - path: apps/web - ########## Generate image tag and build Docker image ########## - - name: Generate Docker image tag + - name: Generate container image tag id: tag run: | if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then @@ -270,10 +208,6 @@ jobs: echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT ########## Build Image ########## - - name: Extract artifact - working-directory: apps/web - run: unzip web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip - - name: Generate image full name id: image-name env: @@ -283,16 +217,38 @@ jobs: - name: Build Docker image if: ${{ needs.setup.outputs.has_secrets == 'true' }} - id: build-docker + id: build-container uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 with: - context: apps/web + build-args: | + NODE_VERSION=${{ env._NODE_VERSION }} + NPM_COMMAND=${{ matrix.npm_command }} + context: . file: apps/web/Dockerfile - platforms: linux/amd64 + platforms: | + linux/amd64, + linux/arm/v7, + linux/arm64 push: true tags: ${{ steps.image-name.outputs.name }} - secrets: | - "GH_PAT=${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}" + + - name: Zip project + working-directory: apps/web + env: + IMAGE_NAME: ${{ steps.image-name.outputs.name }} + run: | + mkdir build + docker run --rm --volume $(pwd)/build:/temp --entrypoint bash \ + $IMAGE_NAME -c "cp -r ./ /temp" + + zip -r web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip build + + - name: Upload ${{ matrix.artifact_name }} artifact + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + with: + name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip + path: apps/web/web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip + if-no-files-found: error - name: Install Cosign if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' @@ -301,7 +257,7 @@ jobs: - name: Sign image with Cosign if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' env: - DIGEST: ${{ steps.build-docker.outputs.digest }} + DIGEST: ${{ steps.build-container.outputs.digest }} TAGS: ${{ steps.image-name.outputs.name }} run: | IFS="," read -a tags <<< "${TAGS}" @@ -329,19 +285,19 @@ jobs: ref: ${{ contains(github.event_name, 'pull_request') && format('refs/pull/{0}/head', github.event.pull_request.number) || github.ref }} - name: Log out of Docker - run: docker logout + run: docker logout $_AZ_REGISTRY + crowdin-push: name: Crowdin Push if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' - needs: - - build-artifacts - runs-on: ubuntu-22.04 + needs: build-containers + runs-on: ubuntu-24.04 steps: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.event.pull_request.head.sha }} - name: Login to Azure uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 @@ -367,12 +323,12 @@ jobs: upload_sources: true upload_translations: false + trigger-web-vault-deploy: name: Trigger web vault deploy if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' - runs-on: ubuntu-22.04 - needs: - - build-artifacts + runs-on: ubuntu-24.04 + needs: build-containers steps: - name: Login to Azure - CI Subscription uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 @@ -402,13 +358,13 @@ jobs: } }) + check-failures: name: Check for failures if: always() - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: - setup - - build-artifacts - build-containers - crowdin-push - trigger-web-vault-deploy diff --git a/apps/browser/src/auth/popup/sso-v1.component.html b/apps/browser/src/auth/popup/sso-v1.component.html deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/apps/browser/src/auth/popup/sso-v1.component.ts b/apps/browser/src/auth/popup/sso-v1.component.ts deleted file mode 100644 index f56fe697e70..00000000000 --- a/apps/browser/src/auth/popup/sso-v1.component.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Component, Inject } from "@angular/core"; -import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; -import { ActivatedRoute, Router } from "@angular/router"; - -import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component"; -import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; -import { - LoginStrategyServiceAbstraction, - UserDecryptionOptionsServiceAbstraction, -} from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { ToastService } from "@bitwarden/components"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; - -import { BrowserApi } from "../../platform/browser/browser-api"; - -@Component({ - selector: "app-sso", - templateUrl: "sso-v1.component.html", -}) -export class SsoComponentV1 extends BaseSsoComponent { - constructor( - ssoLoginService: SsoLoginServiceAbstraction, - loginStrategyService: LoginStrategyServiceAbstraction, - router: Router, - i18nService: I18nService, - route: ActivatedRoute, - stateService: StateService, - platformUtilsService: PlatformUtilsService, - apiService: ApiService, - cryptoFunctionService: CryptoFunctionService, - passwordGenerationService: PasswordGenerationServiceAbstraction, - syncService: SyncService, - environmentService: EnvironmentService, - logService: LogService, - userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction, - configService: ConfigService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - accountService: AccountService, - private authService: AuthService, - @Inject(WINDOW) private win: Window, - toastService: ToastService, - ) { - super( - ssoLoginService, - loginStrategyService, - router, - i18nService, - route, - stateService, - platformUtilsService, - apiService, - cryptoFunctionService, - environmentService, - passwordGenerationService, - logService, - userDecryptionOptionsService, - configService, - masterPasswordService, - accountService, - toastService, - ); - - environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => { - this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html"; - }); - this.clientId = "browser"; - - this.onSuccessfulLogin = async () => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - syncService.fullSync(true); - - // If the vault is unlocked then this will clear keys from memory, which we don't want to do - if ((await this.authService.getAuthStatus()) !== AuthenticationStatus.Unlocked) { - BrowserApi.reloadOpenWindows(); - } - - this.win.close(); - }; - - this.onSuccessfulLoginTde = async () => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - syncService.fullSync(true); - }; - - this.onSuccessfulLoginTdeNavigate = async () => { - this.win.close(); - }; - } -} diff --git a/apps/browser/src/autofill/background/overlay-notifications.background.spec.ts b/apps/browser/src/autofill/background/overlay-notifications.background.spec.ts index 57930496978..a51757dabea 100644 --- a/apps/browser/src/autofill/background/overlay-notifications.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay-notifications.background.spec.ts @@ -1,8 +1,6 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { EnvironmentServerConfigData } from "@bitwarden/common/platform/models/data/server-config.data"; @@ -25,8 +23,6 @@ import { OverlayNotificationsBackground } from "./overlay-notifications.backgrou describe("OverlayNotificationsBackground", () => { let logService: MockProxy; - let getFeatureFlagMock$: BehaviorSubject; - let configService: MockProxy; let notificationBackground: NotificationBackground; let getEnableChangedPasswordPromptSpy: jest.SpyInstance; let getEnableAddedLoginPromptSpy: jest.SpyInstance; @@ -35,10 +31,6 @@ describe("OverlayNotificationsBackground", () => { beforeEach(async () => { jest.useFakeTimers(); logService = mock(); - getFeatureFlagMock$ = new BehaviorSubject(true); - configService = mock({ - getFeatureFlag$: jest.fn().mockReturnValue(getFeatureFlagMock$), - }); notificationBackground = mock(); getEnableChangedPasswordPromptSpy = jest .spyOn(notificationBackground, "getEnableChangedPasswordPrompt") @@ -48,10 +40,8 @@ describe("OverlayNotificationsBackground", () => { .mockResolvedValue(true); overlayNotificationsBackground = new OverlayNotificationsBackground( logService, - configService, notificationBackground, ); - configService.getFeatureFlag.mockResolvedValue(true); await overlayNotificationsBackground.init(); }); @@ -60,27 +50,6 @@ describe("OverlayNotificationsBackground", () => { jest.clearAllTimers(); }); - describe("feature flag behavior", () => { - let runtimeRemoveListenerSpy: jest.SpyInstance; - - beforeEach(() => { - runtimeRemoveListenerSpy = jest.spyOn(chrome.runtime.onMessage, "removeListener"); - }); - - it("removes the extension listeners if the current flag value is set to `false`", () => { - getFeatureFlagMock$.next(false); - - expect(runtimeRemoveListenerSpy).toHaveBeenCalled(); - }); - - it("ignores the feature flag change if the previous flag value is equal to the current flag value", () => { - getFeatureFlagMock$.next(false); - getFeatureFlagMock$.next(false); - - expect(runtimeRemoveListenerSpy).toHaveBeenCalledTimes(1); - }); - }); - describe("setting up the form submission listeners", () => { let fields: MockProxy[]; let details: MockProxy; diff --git a/apps/browser/src/autofill/background/overlay-notifications.background.ts b/apps/browser/src/autofill/background/overlay-notifications.background.ts index ce30dd462b3..5c85ce132d7 100644 --- a/apps/browser/src/autofill/background/overlay-notifications.background.ts +++ b/apps/browser/src/autofill/background/overlay-notifications.background.ts @@ -1,11 +1,8 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { startWith, Subject, Subscription, switchMap, timer } from "rxjs"; -import { pairwise } from "rxjs/operators"; +import { Subject, switchMap, timer } from "rxjs"; import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { BrowserApi } from "../../platform/browser/browser-api"; @@ -26,7 +23,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg private websiteOriginsWithFields: WebsiteOriginsWithFields = new Map(); private activeFormSubmissionRequests: ActiveFormSubmissionRequests = new Set(); private modifyLoginCipherFormData: ModifyLoginCipherFormDataForTab = new Map(); - private featureFlagState$: Subscription; private clearLoginCipherFormDataSubject: Subject = new Subject(); private notificationFallbackTimeout: number | NodeJS.Timeout | null; private readonly formSubmissionRequestMethods: Set = new Set(["POST", "PUT", "PATCH"]); @@ -38,7 +34,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg constructor( private logService: LogService, - private configService: ConfigService, private notificationBackground: NotificationBackground, ) {} @@ -46,35 +41,13 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg * Initialize the overlay notifications background service. */ async init() { - this.featureFlagState$ = this.configService - .getFeatureFlag$(FeatureFlag.NotificationBarAddLoginImprovements) - .pipe(startWith(undefined), pairwise()) - .subscribe(([prev, current]) => this.handleInitFeatureFlagChange(prev, current)); + this.setupExtensionListeners(); + this.clearLoginCipherFormDataSubject .pipe(switchMap(() => timer(CLEAR_NOTIFICATION_LOGIN_DATA_DURATION))) .subscribe(() => this.modifyLoginCipherFormData.clear()); } - /** - * Handles enabling/disabling the extension listeners that trigger the - * overlay notifications based on the feature flag state. - * - * @param previousValue - The previous value of the feature flag - * @param currentValue - The current value of the feature flag - */ - private handleInitFeatureFlagChange = (previousValue: boolean, currentValue: boolean) => { - if (previousValue === currentValue) { - return; - } - - if (currentValue) { - this.setupExtensionListeners(); - return; - } - - this.removeExtensionListeners(); - }; - /** * Handles the response from the content script with the page details. Triggers an initialization * of the add login or change password notification if the conditions are met. @@ -520,15 +493,6 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg chrome.tabs.onUpdated.addListener(this.handleTabUpdated); } - /** - * Removes the listeners for the extension messages and the tab events. - */ - private removeExtensionListeners() { - BrowserApi.removeListener(chrome.runtime.onMessage, this.handleExtensionMessage); - chrome.tabs.onRemoved.removeListener(this.handleTabRemoved); - chrome.tabs.onUpdated.removeListener(this.handleTabUpdated); - } - /** * Handles messages that are sent to the extension background. * diff --git a/apps/browser/src/autofill/content/notification-bar.ts b/apps/browser/src/autofill/content/notification-bar.ts deleted file mode 100644 index bf3d562a0ef..00000000000 --- a/apps/browser/src/autofill/content/notification-bar.ts +++ /dev/null @@ -1,1082 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config"; - -import { - AddLoginMessageData, - ChangePasswordMessageData, -} from "../background/abstractions/notification.background"; -import AutofillField from "../models/autofill-field"; -import { WatchedForm } from "../models/watched-form"; -import { NotificationBarIframeInitData } from "../notification/abstractions/notification-bar"; -import { NotificationTypeData } from "../overlay/notifications/abstractions/overlay-notifications-content.service"; -import { FormData } from "../services/abstractions/autofill.service"; -import { sendExtensionMessage, setupExtensionDisconnectAction } from "../utils"; - -interface HTMLElementWithFormOpId extends HTMLElement { - formOpId: string; -} - -/** - * @fileoverview This file contains the code for the Bitwarden Notification Bar content script. - * The notification bar is used to notify logged in users that they can - * save a new login, change a existing password on a password change screen, - * or update an existing login after detecting a different password on login. - * - * Note: content scripts are reloaded on non-SPA page change. - */ - -/* - * Run content script when the DOM is fully loaded - * - * The DOMContentLoaded event fires when the HTML document has been completely parsed, - * and all deferred scripts (