From 33f7643e15b229c9e85a77cfe11165863d790baf Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 19 Nov 2024 13:59:59 +0100 Subject: [PATCH] [PM-12989] Create process for qa to build client with particular sdk version (#11601) * feat: update sdk service abstraction with documentation and new `userClient$` function * feat: add uninitialized user client with cache * feat: initialize user crypto * feat: initialize org keys * fix: org crypto not initializing properly * feat: avoid creating clients unnecessarily * chore: remove dev print/subscription * fix: clean up cache * chore: update sdk version * feat: implement clean-up logic (#11504) * chore: bump sdk version to fix build issues * chore: bump sdk version to fix build issues * fix: missing constructor parameters * refactor: simplify free() and delete() calls * refactor: use a named function for client creation * fix: client never freeing after refactor * fix: broken impl and race condition in tests * feat: add sdk override to desktop build * feat: add SDK version to browser about dialog * feat: add sdk override to browser build * fix: `npm ci` overriding the override * fix: artifacts not properly downloaded * fix: switch to new repository * feat: add debug version function to web * feat: add sdk-version to CLI * feat: add version to desktop * feat: add override to cli * feat: add override to web * fix: cli version acting as default command * fix: consistent workflow input name * feat: add error handling * feat: upgrade sdk-internal * fix: forgot to update package lock * fix: broken CI build move sdk version to a regular command * chore: revert version changes * refactor: move error handling code * chore: bump SDK to 0.2.0.main-1 * fix: clean up references to inputs.sdk_commit * refactor: rename `init` to `applyVersionToWindow` --- .github/workflows/build-browser.yml | 44 +++++- .github/workflows/build-cli.yml | 46 ++++++- .github/workflows/build-desktop.yml | 126 +++++++++++++++++- .github/workflows/build-web.yml | 24 ++++ .../about-dialog/about-dialog.component.html | 1 + .../about-dialog/about-dialog.component.ts | 4 + apps/cli/src/program.ts | 9 ++ apps/desktop/src/app/services/init.service.ts | 4 + apps/desktop/src/main.ts | 5 + apps/desktop/src/main/menu/menu.about.ts | 7 + apps/desktop/src/main/menu/menu.main.ts | 3 + apps/desktop/src/main/menu/menubar.ts | 4 +- .../desktop/src/platform/main/version.main.ts | 17 +++ apps/desktop/src/platform/preload.ts | 7 + .../src/platform/services/version.service.ts | 18 +++ apps/web/src/app/core/init.service.ts | 5 + apps/web/src/app/platform/version.service.ts | 34 +++++ .../platform/abstractions/sdk/sdk.service.ts | 5 + .../services/sdk/default-sdk.service.ts | 6 + 19 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 apps/desktop/src/platform/main/version.main.ts create mode 100644 apps/desktop/src/platform/services/version.service.ts create mode 100644 apps/web/src/app/platform/version.service.ts diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 42d012d5a9..1b3ad67fc9 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -27,7 +27,11 @@ on: workflow_call: inputs: {} workflow_dispatch: - inputs: {} + inputs: + sdk_branch: + description: "Custom SDK branch" + required: false + type: string defaults: run: @@ -168,6 +172,25 @@ jobs: run: npm ci working-directory: browser-source/ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: browser-source/ + run: | + npm link ../sdk-internal + - name: Build run: npm run dist working-directory: browser-source/apps/browser @@ -331,6 +354,25 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + npm link ../sdk-internal + - name: Build Safari extension run: npm run dist:safari working-directory: apps/browser diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index ac39ab2608..883dc61f49 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -28,7 +28,11 @@ on: - '.github/workflows/build-cli.yml' - 'bitwarden_license/bit-cli/**' workflow_dispatch: - inputs: {} + inputs: + sdk_branch: + description: "Custom SDK branch" + required: false + type: string defaults: run: @@ -112,6 +116,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Build & Package Unix run: npm run dist:${{ matrix.license_type.build_prefix }}:${{ env.SHORT_RUNNER_OS }} --quiet @@ -247,6 +271,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Build & Package Windows run: npm run dist:${{ matrix.license_type.build_prefix }}:win --quiet diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index d21f4ac65b..27995f1c78 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -26,7 +26,11 @@ on: - '!*.txt' - '.github/workflows/build-desktop.yml' workflow_dispatch: - inputs: {} + inputs: + sdk_branch: + description: "Custom SDK branch" + required: false + type: string defaults: run: @@ -182,6 +186,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache @@ -328,6 +352,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache @@ -616,6 +660,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache @@ -784,6 +848,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache @@ -1012,6 +1096,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache @@ -1247,6 +1351,26 @@ jobs: run: npm ci working-directory: ./ + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Cache Native Module uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 7e89a5c7cd..350835d0ec 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -32,6 +32,10 @@ on: custom_tag_extension: description: "Custom image tag extension" required: false + sdk_branch: + description: "Custom SDK branch" + required: false + type: string env: _AZ_REGISTRY: bitwardenprod.azurecr.io @@ -124,6 +128,26 @@ jobs: - name: Install dependencies run: npm ci + - name: Download SDK Artifacts + if: ${{ inputs.sdk_branch != '' }} + 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 != '' }} + working-directory: ./ + run: | + ls -l ../ + npm link ../sdk-internal + - name: Add Git metadata to build version working-directory: apps/web if: matrix.git_metadata diff --git a/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.html b/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.html index bad39a53d3..eceeaf19cb 100644 --- a/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.html +++ b/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.html @@ -6,6 +6,7 @@

© Bitwarden Inc. 2015-{{ year }}

{{ "version" | i18n }}: {{ version$ | async }}

+

SDK: {{ sdkVersion$ | async }}

{{ "serverVersion" | i18n }}: {{ data.serverConfig?.version }} diff --git a/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.ts b/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.ts index 0467debdfb..f730fef24b 100644 --- a/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.ts +++ b/apps/browser/src/tools/popup/settings/about-dialog/about-dialog.component.ts @@ -6,6 +6,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; import { ButtonModule, DialogModule } from "@bitwarden/components"; @Component({ @@ -22,10 +23,13 @@ export class AboutDialogComponent { this.environmentService.environment$.pipe(map((env) => env.isCloud())), ]).pipe(map(([serverConfig, isCloud]) => ({ serverConfig, isCloud }))); + protected sdkVersion$ = this.sdkService.version$; + constructor( private configService: ConfigService, private environmentService: EnvironmentService, private platformUtilsService: PlatformUtilsService, + private sdkService: SdkService, ) { this.version$ = defer(() => this.platformUtilsService.getApplicationVersion()); } diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index 7e0f75de4e..ca2adb8575 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -1,5 +1,6 @@ import * as chalk from "chalk"; import { program, Command, OptionValues } from "commander"; +import { firstValueFrom } from "rxjs"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -102,6 +103,14 @@ export class Program extends BaseProgram { writeLn("", true); }); + program + .command("sdk-version") + .description("Print the SDK version.") + .action(async () => { + const sdkVersion = await firstValueFrom(this.serviceContainer.sdkService.version$); + writeLn(sdkVersion, true); + }); + program .command("login [email] [password]") .description("Log into a user account.") diff --git a/apps/desktop/src/app/services/init.service.ts b/apps/desktop/src/app/services/init.service.ts index 627a9b6222..0068a03d68 100644 --- a/apps/desktop/src/app/services/init.service.ts +++ b/apps/desktop/src/app/services/init.service.ts @@ -22,6 +22,7 @@ import { KeyService as KeyServiceAbstraction } from "@bitwarden/key-management"; import { I18nRendererService } from "../../platform/services/i18n.renderer.service"; import { SshAgentService } from "../../platform/services/ssh-agent.service"; +import { VersionService } from "../../platform/services/version.service"; import { NativeMessagingService } from "../../services/native-messaging.service"; @Injectable() @@ -42,6 +43,7 @@ export class InitService { private encryptService: EncryptService, private userAutoUnlockKeyService: UserAutoUnlockKeyService, private accountService: AccountService, + private versionService: VersionService, private sshAgentService: SshAgentService, @Inject(DOCUMENT) private document: Document, ) {} @@ -76,6 +78,8 @@ export class InitService { htmlEl.classList.add("os_" + this.platformUtilsService.getDeviceString()); this.themingService.applyThemeChangesTo(this.document); + this.versionService.init(); + const containerService = new ContainerService(this.keyService, this.encryptService); containerService.attachToGlobal(this.win); }; diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index f869898d57..bbb5c23513 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -39,6 +39,7 @@ import { ClipboardMain } from "./platform/main/clipboard.main"; import { DesktopCredentialStorageListener } from "./platform/main/desktop-credential-storage-listener"; import { MainCryptoFunctionService } from "./platform/main/main-crypto-function.service"; import { MainSshAgentService } from "./platform/main/main-ssh-agent.service"; +import { VersionMain } from "./platform/main/version.main"; import { DesktopSettingsService } from "./platform/services/desktop-settings.service"; import { ElectronLogMainService } from "./platform/services/electron-log.main.service"; import { ElectronStorageService } from "./platform/services/electron-storage.service"; @@ -72,6 +73,7 @@ export class Main { nativeMessagingMain: NativeMessagingMain; clipboardMain: ClipboardMain; desktopAutofillSettingsService: DesktopAutofillSettingsService; + versionMain: VersionMain; sshAgentService: MainSshAgentService; constructor() { @@ -199,6 +201,8 @@ export class Main { }); }); + this.versionMain = new VersionMain(this.windowMain); + this.powerMonitorMain = new PowerMonitorMain(this.messagingService, this.logService); this.menuMain = new MenuMain( this.i18nService, @@ -207,6 +211,7 @@ export class Main { this.windowMain, this.updaterMain, this.desktopSettingsService, + this.versionMain, ); this.biometricsService = new BiometricsService( diff --git a/apps/desktop/src/main/menu/menu.about.ts b/apps/desktop/src/main/menu/menu.about.ts index 50e125b3d6..bd82d73fcb 100644 --- a/apps/desktop/src/main/menu/menu.about.ts +++ b/apps/desktop/src/main/menu/menu.about.ts @@ -2,6 +2,7 @@ import { BrowserWindow, clipboard, dialog, MenuItemConstructorOptions } from "el import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { VersionMain } from "../../platform/main/version.main"; import { isMacAppStore, isSnapStore, isWindowsStore } from "../../utils"; import { UpdaterMain } from "../updater.main"; @@ -22,17 +23,20 @@ export class AboutMenu implements IMenubarMenu { private readonly _updater: UpdaterMain; private readonly _window: BrowserWindow; private readonly _version: string; + private readonly _versionMain: VersionMain; constructor( i18nService: I18nService, version: string, window: BrowserWindow, updater: UpdaterMain, + versionMain: VersionMain, ) { this._i18nService = i18nService; this._updater = updater; this._version = version; this._window = window; + this._versionMain = versionMain; } private get separator(): MenuItemConstructorOptions { @@ -53,8 +57,11 @@ export class AboutMenu implements IMenubarMenu { id: "aboutBitwarden", label: this.localize("aboutBitwarden"), click: async () => { + const sdkVersion = await this._versionMain.sdkVersion(); const aboutInformation = this.localize("version", this._version) + + "\nSDK " + + sdkVersion + "\nShell " + process.versions.electron + "\nRenderer " + diff --git a/apps/desktop/src/main/menu/menu.main.ts b/apps/desktop/src/main/menu/menu.main.ts index 9a63d389b5..eafadf3bfb 100644 --- a/apps/desktop/src/main/menu/menu.main.ts +++ b/apps/desktop/src/main/menu/menu.main.ts @@ -5,6 +5,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { VersionMain } from "../../platform/main/version.main"; import { DesktopSettingsService } from "../../platform/services/desktop-settings.service"; import { UpdaterMain } from "../updater.main"; import { WindowMain } from "../window.main"; @@ -22,6 +23,7 @@ export class MenuMain { private windowMain: WindowMain, private updaterMain: UpdaterMain, private desktopSettingsService: DesktopSettingsService, + private versionMain: VersionMain, ) {} async init() { @@ -44,6 +46,7 @@ export class MenuMain { await this.getWebVaultUrl(), app.getVersion(), await firstValueFrom(this.desktopSettingsService.hardwareAcceleration$), + this.versionMain, updateRequest, ).menu, ); diff --git a/apps/desktop/src/main/menu/menubar.ts b/apps/desktop/src/main/menu/menubar.ts index b71774c5af..f69174b9a3 100644 --- a/apps/desktop/src/main/menu/menubar.ts +++ b/apps/desktop/src/main/menu/menubar.ts @@ -3,6 +3,7 @@ import { Menu, MenuItemConstructorOptions } from "electron"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { VersionMain } from "../../platform/main/version.main"; import { DesktopSettingsService } from "../../platform/services/desktop-settings.service"; import { isMac } from "../../utils"; import { UpdaterMain } from "../updater.main"; @@ -54,6 +55,7 @@ export class Menubar { webVaultUrl: string, appVersion: string, hardwareAccelerationEnabled: boolean, + versionMain: VersionMain, updateRequest?: MenuUpdateRequest, ) { let isLocked = true; @@ -96,7 +98,7 @@ export class Menubar { desktopSettingsService, webVaultUrl, hardwareAccelerationEnabled, - new AboutMenu(i18nService, appVersion, windowMain.win, updaterMain), + new AboutMenu(i18nService, appVersion, windowMain.win, updaterMain, versionMain), ), ]; diff --git a/apps/desktop/src/platform/main/version.main.ts b/apps/desktop/src/platform/main/version.main.ts new file mode 100644 index 0000000000..1c39b641d2 --- /dev/null +++ b/apps/desktop/src/platform/main/version.main.ts @@ -0,0 +1,17 @@ +import { ipcMain } from "electron"; + +import { WindowMain } from "../../main/window.main"; + +export class VersionMain { + constructor(private windowMain: WindowMain) {} + + sdkVersion() { + const timeout = new Promise((resolve) => setTimeout(() => resolve("Timeout error"), 1000)); + const version = new Promise((resolve) => { + ipcMain.once("sdkVersion", (_, version) => resolve(version)); + this.windowMain.win.webContents.send("sdkVersion"); + }); + + return Promise.race([timeout, version]); + } +} diff --git a/apps/desktop/src/platform/preload.ts b/apps/desktop/src/platform/preload.ts index 35caeff27c..171e83bbef 100644 --- a/apps/desktop/src/platform/preload.ts +++ b/apps/desktop/src/platform/preload.ts @@ -122,6 +122,13 @@ const localhostCallbackService = { export default { versions: { app: (): Promise => ipcRenderer.invoke("appVersion"), + registerSdkVersionProvider: (provide: (resolve: (version: string) => void) => void) => { + const resolve = (version: string) => ipcRenderer.send("sdkVersion", version); + + ipcRenderer.on("sdkVersion", () => { + provide(resolve); + }); + }, }, deviceType: deviceType(), isDev: isDev(), diff --git a/apps/desktop/src/platform/services/version.service.ts b/apps/desktop/src/platform/services/version.service.ts new file mode 100644 index 0000000000..2628f83d59 --- /dev/null +++ b/apps/desktop/src/platform/services/version.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from "@angular/core"; +import { firstValueFrom } from "rxjs"; + +import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; + +@Injectable({ + providedIn: "root", +}) +export class VersionService { + constructor(private sdkService: SdkService) {} + + init() { + ipc.platform.versions.registerSdkVersionProvider(async (resolve) => { + const version = await firstValueFrom(this.sdkService.version$); + resolve(version); + }); + } +} diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts index 4bd0ff1f48..b3e6d691f7 100644 --- a/apps/web/src/app/core/init.service.ts +++ b/apps/web/src/app/core/init.service.ts @@ -17,6 +17,8 @@ import { EventUploadService } from "@bitwarden/common/services/event/event-uploa import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; import { KeyService as KeyServiceAbstraction } from "@bitwarden/key-management"; +import { VersionService } from "../platform/version.service"; + @Injectable() export class InitService { constructor( @@ -32,6 +34,7 @@ export class InitService { private encryptService: EncryptService, private userAutoUnlockKeyService: UserAutoUnlockKeyService, private accountService: AccountService, + private versionService: VersionService, @Inject(DOCUMENT) private document: Document, ) {} @@ -54,6 +57,8 @@ export class InitService { const htmlEl = this.win.document.documentElement; htmlEl.classList.add("locale_" + this.i18nService.translationLocale); this.themingService.applyThemeChangesTo(this.document); + this.versionService.applyVersionToWindow(); + const containerService = new ContainerService(this.keyService, this.encryptService); containerService.attachToGlobal(this.win); }; diff --git a/apps/web/src/app/platform/version.service.ts b/apps/web/src/app/platform/version.service.ts new file mode 100644 index 0000000000..d82dc5590d --- /dev/null +++ b/apps/web/src/app/platform/version.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from "@angular/core"; +import { catchError, firstValueFrom, map } from "rxjs"; + +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service"; + +type Version = { + client: string; + sdk: string; +}; + +@Injectable({ + providedIn: "root", +}) +export class VersionService { + constructor( + private platformUtilsService: PlatformUtilsService, + private sdkService: SdkService, + ) {} + + applyVersionToWindow() { + (window as any).__version = async (): Promise => { + return { + client: await this.platformUtilsService.getApplicationVersion(), + sdk: await firstValueFrom( + this.sdkService.client$.pipe( + map((client) => client.version()), + catchError(() => "Unsupported"), + ), + ), + }; + }; + } +} diff --git a/libs/common/src/platform/abstractions/sdk/sdk.service.ts b/libs/common/src/platform/abstractions/sdk/sdk.service.ts index 00c14bdfac..5e496c06bd 100644 --- a/libs/common/src/platform/abstractions/sdk/sdk.service.ts +++ b/libs/common/src/platform/abstractions/sdk/sdk.service.ts @@ -10,6 +10,11 @@ export abstract class SdkService { */ supported$: Observable; + /** + * Retrieve the version of the SDK. + */ + version$: Observable; + /** * Retrieve a client initialized without a user. * This client can only be used for operations that don't require a user context. diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index b25ede006c..ccadfe7cca 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -8,6 +8,7 @@ import { distinctUntilChanged, tap, switchMap, + catchError, } from "rxjs"; import { KeyService } from "@bitwarden/key-management"; @@ -51,6 +52,11 @@ export class DefaultSdkService implements SdkService { }), ); + version$ = this.client$.pipe( + map((client) => client.version()), + catchError(() => "Unsupported"), + ); + constructor( private sdkClientFactory: SdkClientFactory, private environmentService: EnvironmentService,