1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 09:43:23 +00:00

Merge branch 'main' into auth/pm-8111/browser-refresh-login-component

This commit is contained in:
Alec Rippberger
2024-10-07 14:31:11 -05:00
86 changed files with 1088 additions and 574 deletions

View File

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

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bitwarden/browser", "name": "@bitwarden/browser",
"version": "2024.10.0", "version": "2024.10.1",
"scripts": { "scripts": {
"build": "cross-env MANIFEST_VERSION=3 webpack", "build": "cross-env MANIFEST_VERSION=3 webpack",
"build:mv2": "webpack", "build:mv2": "webpack",

View File

@@ -90,6 +90,7 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
import { import {
AbstractStorageService, AbstractStorageService,
@@ -122,6 +123,8 @@ import { FileUploadService } from "@bitwarden/common/platform/services/file-uplo
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service"; import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/default-sdk.service";
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
import { StateService } from "@bitwarden/common/platform/services/state.service"; import { StateService } from "@bitwarden/common/platform/services/state.service";
import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { SystemService } from "@bitwarden/common/platform/services/system.service";
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
@@ -228,6 +231,7 @@ import AutofillService from "../autofill/services/autofill.service";
import { SafariApp } from "../browser/safariApp"; import { SafariApp } from "../browser/safariApp";
import { BackgroundBrowserBiometricsService } from "../key-management/biometrics/background-browser-biometrics.service"; import { BackgroundBrowserBiometricsService } from "../key-management/biometrics/background-browser-biometrics.service";
import { BrowserApi } from "../platform/browser/browser-api"; import { BrowserApi } from "../platform/browser/browser-api";
import { flagEnabled } from "../platform/flags";
import { UpdateBadge } from "../platform/listeners/update-badge"; import { UpdateBadge } from "../platform/listeners/update-badge";
/* eslint-disable no-restricted-imports */ /* eslint-disable no-restricted-imports */
import { ChromeMessageSender } from "../platform/messaging/chrome-message.sender"; import { ChromeMessageSender } from "../platform/messaging/chrome-message.sender";
@@ -245,6 +249,7 @@ import { LocalBackedSessionStorageService } from "../platform/services/local-bac
import { BackgroundPlatformUtilsService } from "../platform/services/platform-utils/background-platform-utils.service"; import { BackgroundPlatformUtilsService } from "../platform/services/platform-utils/background-platform-utils.service";
import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service"; import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service";
import { PopupViewCacheBackgroundService } from "../platform/services/popup-view-cache-background.service"; import { PopupViewCacheBackgroundService } from "../platform/services/popup-view-cache-background.service";
import { BrowserSdkClientFactory } from "../platform/services/sdk/browser-sdk-client-factory";
import { BackgroundTaskSchedulerService } from "../platform/services/task-scheduler/background-task-scheduler.service"; import { BackgroundTaskSchedulerService } from "../platform/services/task-scheduler/background-task-scheduler.service";
import { ForegroundTaskSchedulerService } from "../platform/services/task-scheduler/foreground-task-scheduler.service"; import { ForegroundTaskSchedulerService } from "../platform/services/task-scheduler/foreground-task-scheduler.service";
import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service"; import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service";
@@ -364,6 +369,7 @@ export default class MainBackground {
syncServiceListener: SyncServiceListener; syncServiceListener: SyncServiceListener;
themeStateService: DefaultThemeStateService; themeStateService: DefaultThemeStateService;
autoSubmitLoginBackground: AutoSubmitLoginBackground; autoSubmitLoginBackground: AutoSubmitLoginBackground;
sdkService: SdkService;
onUpdatedRan: boolean; onUpdatedRan: boolean;
onReplacedRan: boolean; onReplacedRan: boolean;
@@ -719,6 +725,16 @@ export default class MainBackground {
this.stateProvider, this.stateProvider,
); );
const sdkClientFactory = flagEnabled("sdk")
? new BrowserSdkClientFactory()
: new NoopSdkClientFactory();
this.sdkService = new DefaultSdkService(
sdkClientFactory,
this.environmentService,
this.platformUtilsService,
this.apiService,
);
this.passwordStrengthService = new PasswordStrengthService(); this.passwordStrengthService = new PasswordStrengthService();
this.passwordGenerationService = legacyPasswordGenerationServiceFactory( this.passwordGenerationService = legacyPasswordGenerationServiceFactory(
@@ -1315,6 +1331,20 @@ export default class MainBackground {
await this.initOverlayAndTabsBackground(); await this.initOverlayAndTabsBackground();
if (flagEnabled("sdk")) {
// Warn if the SDK for some reason can't be initialized
let supported = false;
try {
supported = await firstValueFrom(this.sdkService.supported$);
} catch (e) {
// Do nothing.
}
if (!supported) {
this.sdkService.failedToInitialize().catch(this.logService.error);
}
}
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
setTimeout(async () => { setTimeout(async () => {
await this.refreshBadge(); await this.refreshBadge();

View File

@@ -2,7 +2,7 @@
"manifest_version": 2, "manifest_version": 2,
"name": "__MSG_extName__", "name": "__MSG_extName__",
"short_name": "__MSG_appName__", "short_name": "__MSG_appName__",
"version": "2024.10.0", "version": "2024.10.1",
"description": "__MSG_extDesc__", "description": "__MSG_extDesc__",
"default_locale": "en", "default_locale": "en",
"author": "Bitwarden Inc.", "author": "Bitwarden Inc.",

View File

@@ -3,7 +3,7 @@
"minimum_chrome_version": "102.0", "minimum_chrome_version": "102.0",
"name": "__MSG_extName__", "name": "__MSG_extName__",
"short_name": "__MSG_appName__", "short_name": "__MSG_appName__",
"version": "2024.10.0", "version": "2024.10.1",
"description": "__MSG_extDesc__", "description": "__MSG_extDesc__",
"default_locale": "en", "default_locale": "en",
"author": "Bitwarden Inc.", "author": "Bitwarden Inc.",
@@ -39,8 +39,7 @@
} }
], ],
"background": { "background": {
"service_worker": "background.js", "service_worker": "background.js"
"type": "module"
}, },
"action": { "action": {
"default_icon": { "default_icon": {

View File

@@ -0,0 +1,66 @@
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import type { BitwardenClient } from "@bitwarden/sdk-internal";
import { BrowserApi } from "../../browser/browser-api";
// https://stackoverflow.com/a/47880734
const supported = (() => {
try {
if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
const module = new WebAssembly.Module(
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00),
);
if (module instanceof WebAssembly.Module) {
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
}
}
} catch (e) {
// ignore
}
return false;
})();
// Manifest v3 does not support dynamic imports in the service worker.
if (BrowserApi.isManifestVersion(3)) {
if (supported) {
// eslint-disable-next-line no-console
console.debug("WebAssembly is supported in this environment");
import("./wasm");
} else {
// eslint-disable-next-line no-console
console.debug("WebAssembly is not supported in this environment");
import("./fallback");
}
}
// Manifest v2 expects dynamic imports to prevent timing issues.
async function load() {
if (BrowserApi.isManifestVersion(3)) {
return;
}
if (supported) {
// eslint-disable-next-line no-console
console.debug("WebAssembly is supported in this environment");
await import("./wasm");
} else {
// eslint-disable-next-line no-console
console.debug("WebAssembly is not supported in this environment");
await import("./fallback");
}
}
/**
* SDK client factory with a js fallback for when WASM is not supported.
*
* Works both in popup and service worker.
*/
export class BrowserSdkClientFactory implements SdkClientFactory {
async createSdkClient(
...args: ConstructorParameters<typeof BitwardenClient>
): Promise<BitwardenClient> {
await load();
return Promise.resolve((globalThis as any).init_sdk(...args));
}
}

View File

@@ -0,0 +1,8 @@
import * as sdk from "@bitwarden/sdk-internal";
import * as wasm from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm.js";
(globalThis as any).init_sdk = (...args: ConstructorParameters<typeof sdk.BitwardenClient>) => {
(sdk as any).init(wasm);
return new sdk.BitwardenClient(...args);
};

View File

@@ -0,0 +1,8 @@
import * as sdk from "@bitwarden/sdk-internal";
import * as wasm from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm";
(globalThis as any).init_sdk = (...args: ConstructorParameters<typeof sdk.BitwardenClient>) => {
(sdk as any).init(wasm);
return new sdk.BitwardenClient(...args);
};

View File

@@ -1,6 +1,7 @@
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, inject } from "@angular/core"; import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit, inject } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { NavigationEnd, Router, RouterOutlet } from "@angular/router"; import { NavigationEnd, Router, RouterOutlet } from "@angular/router";
import { Subject, takeUntil, firstValueFrom, concatMap, filter, tap } from "rxjs"; import { Subject, takeUntil, firstValueFrom, concatMap, filter, tap, catchError, of } from "rxjs";
import { LogoutReason } from "@bitwarden/auth/common"; import { LogoutReason } from "@bitwarden/auth/common";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@@ -8,7 +9,9 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service"; import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { MessageListener } from "@bitwarden/common/platform/messaging"; import { MessageListener } from "@bitwarden/common/platform/messaging";
import { UserId } from "@bitwarden/common/types/guid"; import { UserId } from "@bitwarden/common/types/guid";
@@ -20,6 +23,7 @@ import {
ToastService, ToastService,
} from "@bitwarden/components"; } from "@bitwarden/components";
import { flagEnabled } from "../platform/flags";
import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service"; import { PopupViewCacheService } from "../platform/popup/view-cache/popup-view-cache.service";
import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service"; import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service";
import { BrowserSendStateService } from "../tools/popup/services/browser-send-state.service"; import { BrowserSendStateService } from "../tools/popup/services/browser-send-state.service";
@@ -62,7 +66,28 @@ export class AppComponent implements OnInit, OnDestroy {
private toastService: ToastService, private toastService: ToastService,
private accountService: AccountService, private accountService: AccountService,
private animationControlService: AnimationControlService, private animationControlService: AnimationControlService,
) {} private logService: LogService,
private sdkService: SdkService,
) {
if (flagEnabled("sdk")) {
// Warn if the SDK for some reason can't be initialized
this.sdkService.supported$
.pipe(
takeUntilDestroyed(),
catchError(() => {
return of(false);
}),
)
.subscribe((supported) => {
if (!supported) {
this.logService.debug("SDK is not supported");
this.sdkService.failedToInitialize().catch(this.logService.error);
} else {
this.logService.debug("SDK is supported");
}
});
}
}
async ngOnInit() { async ngOnInit() {
initPopupClosedListener(); initPopupClosedListener();

View File

@@ -72,6 +72,7 @@ import {
PlatformUtilsService, PlatformUtilsService,
PlatformUtilsService as PlatformUtilsServiceAbstraction, PlatformUtilsService as PlatformUtilsServiceAbstraction,
} from "@bitwarden/common/platform/abstractions/platform-utils.service"; } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { import {
AbstractStorageService, AbstractStorageService,
@@ -80,9 +81,11 @@ import {
import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging"; import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging";
// eslint-disable-next-line no-restricted-imports -- Used for dependency injection // eslint-disable-next-line no-restricted-imports -- Used for dependency injection
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
import { flagEnabled } from "@bitwarden/common/platform/misc/flags";
import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling"; import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling";
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service";
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service";
import { import {
@@ -130,6 +133,7 @@ import BrowserLocalStorageService from "../../platform/services/browser-local-st
import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service"; import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service";
import I18nService from "../../platform/services/i18n.service"; import I18nService from "../../platform/services/i18n.service";
import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service"; import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service";
import { BrowserSdkClientFactory } from "../../platform/services/sdk/browser-sdk-client-factory";
import { ForegroundTaskSchedulerService } from "../../platform/services/task-scheduler/foreground-task-scheduler.service"; import { ForegroundTaskSchedulerService } from "../../platform/services/task-scheduler/foreground-task-scheduler.service";
import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider";
import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service";
@@ -604,6 +608,11 @@ const safeProviders: SafeProvider[] = [
useClass: LoginEmailService, useClass: LoginEmailService,
deps: [AccountService, AuthService, StateProvider], deps: [AccountService, AuthService, StateProvider],
}), }),
safeProvider({
provide: SdkClientFactory,
useClass: flagEnabled("sdk") ? BrowserSdkClientFactory : NoopSdkClientFactory,
deps: [],
}),
]; ];
@NgModule({ @NgModule({

View File

@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
03100CAF291891F4008E14EF /* encrypt-worker.js in Resources */ = {isa = PBXBuildFile; fileRef = 03100CAE291891F4008E14EF /* encrypt-worker.js */; }; 03100CAF291891F4008E14EF /* encrypt-worker.js in Resources */ = {isa = PBXBuildFile; fileRef = 03100CAE291891F4008E14EF /* encrypt-worker.js */; };
55BC93932CB4268A008CA4C6 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 55BC93922CB4268A008CA4C6 /* assets */; };
55E0374D2577FA6B00979016 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E0374C2577FA6B00979016 /* AppDelegate.swift */; }; 55E0374D2577FA6B00979016 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E0374C2577FA6B00979016 /* AppDelegate.swift */; };
55E037502577FA6B00979016 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 55E0374E2577FA6B00979016 /* Main.storyboard */; }; 55E037502577FA6B00979016 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 55E0374E2577FA6B00979016 /* Main.storyboard */; };
55E037522577FA6B00979016 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E037512577FA6B00979016 /* ViewController.swift */; }; 55E037522577FA6B00979016 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E037512577FA6B00979016 /* ViewController.swift */; };
@@ -54,6 +55,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
03100CAE291891F4008E14EF /* encrypt-worker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "encrypt-worker.js"; path = "../../../build/encrypt-worker.js"; sourceTree = "<group>"; }; 03100CAE291891F4008E14EF /* encrypt-worker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "encrypt-worker.js"; path = "../../../build/encrypt-worker.js"; sourceTree = "<group>"; };
5508DD7926051B5900A85C58 /* libswiftAppKit.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftAppKit.tbd; path = usr/lib/swift/libswiftAppKit.tbd; sourceTree = SDKROOT; }; 5508DD7926051B5900A85C58 /* libswiftAppKit.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftAppKit.tbd; path = usr/lib/swift/libswiftAppKit.tbd; sourceTree = SDKROOT; };
55BC93922CB4268A008CA4C6 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = ../../../build/assets; sourceTree = "<group>"; };
55E037482577FA6B00979016 /* desktop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktop.app; sourceTree = BUILT_PRODUCTS_DIR; }; 55E037482577FA6B00979016 /* desktop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktop.app; sourceTree = BUILT_PRODUCTS_DIR; };
55E0374B2577FA6B00979016 /* desktop.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = desktop.entitlements; sourceTree = "<group>"; }; 55E0374B2577FA6B00979016 /* desktop.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = desktop.entitlements; sourceTree = "<group>"; };
55E0374C2577FA6B00979016 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 55E0374C2577FA6B00979016 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -152,6 +154,7 @@
55E0376F2577FA6F00979016 /* Resources */ = { 55E0376F2577FA6F00979016 /* Resources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
55BC93922CB4268A008CA4C6 /* assets */,
03100CAE291891F4008E14EF /* encrypt-worker.js */, 03100CAE291891F4008E14EF /* encrypt-worker.js */,
55E037702577FA6F00979016 /* popup */, 55E037702577FA6F00979016 /* popup */,
55E037712577FA6F00979016 /* background.js */, 55E037712577FA6F00979016 /* background.js */,
@@ -270,6 +273,7 @@
55E0377A2577FA6F00979016 /* background.js in Resources */, 55E0377A2577FA6F00979016 /* background.js in Resources */,
55E037792577FA6F00979016 /* popup in Resources */, 55E037792577FA6F00979016 /* popup in Resources */,
03100CAF291891F4008E14EF /* encrypt-worker.js in Resources */, 03100CAF291891F4008E14EF /* encrypt-worker.js in Resources */,
55BC93932CB4268A008CA4C6 /* assets in Resources */,
55E0377C2577FA6F00979016 /* notification in Resources */, 55E0377C2577FA6F00979016 /* notification in Resources */,
55E0377E2577FA6F00979016 /* vendor.js in Resources */, 55E0377E2577FA6F00979016 /* vendor.js in Resources */,
55E0377D2577FA6F00979016 /* content in Resources */, 55E0377D2577FA6F00979016 /* content in Resources */,

View File

@@ -122,7 +122,7 @@ const moduleRules = [
loader: "@ngtools/webpack", loader: "@ngtools/webpack",
}, },
{ {
test: /\.wasm$/, test: /argon2(-simd)?\.wasm$/,
loader: "base64-loader", loader: "base64-loader",
type: "javascript/auto", type: "javascript/auto",
}, },
@@ -316,13 +316,18 @@ const mainConfig = {
}, },
output: { output: {
filename: "[name].js", filename: "[name].js",
chunkFilename: "assets/[name].js",
webassemblyModuleFilename: "assets/[modulehash].wasm",
path: path.resolve(__dirname, "build"), path: path.resolve(__dirname, "build"),
clean: true, clean: true,
}, },
module: { module: {
noParse: /\.wasm$/, noParse: /argon2(-simd)?\.wasm$/,
rules: moduleRules, rules: moduleRules,
}, },
experiments: {
asyncWebAssembly: true,
},
plugins: plugins, plugins: plugins,
}; };
@@ -395,12 +400,15 @@ if (manifestVersion == 2) {
loader: "ts-loader", loader: "ts-loader",
}, },
{ {
test: /\.wasm$/, test: /argon2(-simd)?\.wasm$/,
loader: "base64-loader", loader: "base64-loader",
type: "javascript/auto", type: "javascript/auto",
}, },
], ],
noParse: /\.wasm$/, noParse: /argon2(-simd)?\.wasm$/,
},
experiments: {
asyncWebAssembly: true,
}, },
resolve: { resolve: {
extensions: [".ts", ".js"], extensions: [".ts", ".js"],

View File

@@ -0,0 +1,5 @@
{
"flags": {
"sdk": true
}
}

View File

@@ -1,7 +1,27 @@
function load(envName) { function load(envName) {
const base = require("./base.json");
const env = loadConfig(envName);
const local = loadConfig("local");
return { return {
...loadConfig(envName), ...base,
...loadConfig("local"), ...env,
...local,
dev: {
...base.dev,
...env.dev,
...local.dev,
},
flags: {
...base.flags,
...env.flags,
...local.flags,
},
devFlags: {
...base.devFlags,
...env.devFlags,
...local.devFlags,
},
}; };
} }

View File

@@ -10,7 +10,11 @@ module.exports = {
preset: "ts-jest", preset: "ts-jest",
testEnvironment: "node", testEnvironment: "node",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"], setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { moduleNameMapper: {
"@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
"<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
...pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/", prefix: "<rootDir>/",
}), }),
},
}; };

View File

@@ -1,7 +1,7 @@
{ {
"name": "@bitwarden/cli", "name": "@bitwarden/cli",
"description": "A secure and free password manager for all of your devices.", "description": "A secure and free password manager for all of your devices.",
"version": "2024.9.1", "version": "2024.10.0",
"keywords": [ "keywords": [
"bitwarden", "bitwarden",
"password", "password",

View File

@@ -64,6 +64,7 @@ import {
RegionConfig, RegionConfig,
} from "@bitwarden/common/platform/abstractions/environment.service"; } from "@bitwarden/common/platform/abstractions/environment.service";
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { KeySuffixOptions, LogLevelType } from "@bitwarden/common/platform/enums"; import { KeySuffixOptions, LogLevelType } from "@bitwarden/common/platform/enums";
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
import { MessageSender } from "@bitwarden/common/platform/messaging"; import { MessageSender } from "@bitwarden/common/platform/messaging";
@@ -86,6 +87,9 @@ import { KeyGenerationService } from "@bitwarden/common/platform/services/key-ge
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory";
import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/default-sdk.service";
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
import { StateService } from "@bitwarden/common/platform/services/state.service"; import { StateService } from "@bitwarden/common/platform/services/state.service";
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
@@ -151,6 +155,7 @@ import {
VaultExportServiceAbstraction, VaultExportServiceAbstraction,
} from "@bitwarden/vault-export-core"; } from "@bitwarden/vault-export-core";
import { flagEnabled } from "../platform/flags";
import { CliPlatformUtilsService } from "../platform/services/cli-platform-utils.service"; import { CliPlatformUtilsService } from "../platform/services/cli-platform-utils.service";
import { ConsoleLogService } from "../platform/services/console-log.service"; import { ConsoleLogService } from "../platform/services/console-log.service";
import { I18nService } from "../platform/services/i18n.service"; import { I18nService } from "../platform/services/i18n.service";
@@ -249,6 +254,7 @@ export class ServiceContainer {
userAutoUnlockKeyService: UserAutoUnlockKeyService; userAutoUnlockKeyService: UserAutoUnlockKeyService;
kdfConfigService: KdfConfigServiceAbstraction; kdfConfigService: KdfConfigServiceAbstraction;
taskSchedulerService: TaskSchedulerService; taskSchedulerService: TaskSchedulerService;
sdkService: SdkService;
constructor() { constructor() {
let p = null; let p = null;
@@ -522,6 +528,17 @@ export class ServiceContainer {
this.globalStateProvider, this.globalStateProvider,
); );
const sdkClientFactory = flagEnabled("sdk")
? new DefaultSdkClientFactory()
: new NoopSdkClientFactory();
this.sdkService = new DefaultSdkService(
sdkClientFactory,
this.environmentService,
this.platformUtilsService,
this.apiService,
customUserAgent,
);
this.passwordStrengthService = new PasswordStrengthService(); this.passwordStrengthService = new PasswordStrengthService();
this.passwordGenerationService = legacyPasswordGenerationServiceFactory( this.passwordGenerationService = legacyPasswordGenerationServiceFactory(
@@ -830,5 +847,19 @@ export class ServiceContainer {
} }
this.inited = true; this.inited = true;
if (flagEnabled("sdk")) {
// Warn if the SDK for some reason can't be initialized
let supported = false;
try {
supported = await firstValueFrom(this.sdkService.supported$);
} catch (e) {
// Do nothing.
}
if (!supported) {
this.sdkService.failedToInitialize().catch(this.logService.error);
}
}
} }
} }

View File

@@ -3,7 +3,7 @@
"pretty": true, "pretty": true,
"moduleResolution": "node", "moduleResolution": "node",
"target": "ES2016", "target": "ES2016",
"module": "es6", "module": "ES2020",
"noImplicitAny": true, "noImplicitAny": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,

View File

@@ -37,8 +37,10 @@ const plugins = [
contextRegExp: /node-fetch/, contextRegExp: /node-fetch/,
}), }),
new webpack.EnvironmentPlugin({ new webpack.EnvironmentPlugin({
ENV: ENV,
BWCLI_ENV: ENV, BWCLI_ENV: ENV,
FLAGS: envConfig.flags, FLAGS: envConfig.flags,
DEV_FLAGS: envConfig.devFlags,
}), }),
new webpack.IgnorePlugin({ new webpack.IgnorePlugin({
resourceRegExp: /canvas/, resourceRegExp: /canvas/,
@@ -79,6 +81,9 @@ const webpackConfig = {
allowlist: [/@bitwarden/], allowlist: [/@bitwarden/],
}), }),
], ],
experiments: {
asyncWebAssembly: true,
},
}; };
module.exports = webpackConfig; module.exports = webpackConfig;

View File

@@ -1,4 +1,6 @@
{ {
"devFlags": {}, "flags": {
"flags": {} "sdk": true
},
"devFlags": {}
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "@bitwarden/desktop", "name": "@bitwarden/desktop",
"description": "A secure and free password manager for all of your devices.", "description": "A secure and free password manager for all of your devices.",
"version": "2024.9.2", "version": "2024.10.0",
"keywords": [ "keywords": [
"bitwarden", "bitwarden",
"password", "password",

View File

@@ -8,8 +8,9 @@ import {
ViewChild, ViewChild,
ViewContainerRef, ViewContainerRef,
} from "@angular/core"; } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { filter, firstValueFrom, map, Subject, takeUntil, timeout } from "rxjs"; import { catchError, filter, firstValueFrom, map, of, Subject, takeUntil, timeout } from "rxjs";
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ModalService } from "@bitwarden/angular/services/modal.service";
@@ -21,7 +22,6 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
@@ -38,6 +38,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { SystemService } from "@bitwarden/common/platform/abstractions/system.service"; import { SystemService } from "@bitwarden/common/platform/abstractions/system.service";
import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize"; import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize";
@@ -56,6 +57,7 @@ import { BiometricStateService } from "@bitwarden/key-management";
import { DeleteAccountComponent } from "../auth/delete-account.component"; import { DeleteAccountComponent } from "../auth/delete-account.component";
import { LoginApprovalComponent } from "../auth/login/login-approval.component"; import { LoginApprovalComponent } from "../auth/login/login-approval.component";
import { MenuAccount, MenuUpdateRequest } from "../main/menu/menu.updater"; import { MenuAccount, MenuUpdateRequest } from "../main/menu/menu.updater";
import { flagEnabled } from "../platform/flags";
import { PremiumComponent } from "../vault/app/accounts/premium.component"; import { PremiumComponent } from "../vault/app/accounts/premium.component";
import { FolderAddEditComponent } from "../vault/app/vault/folder-add-edit.component"; import { FolderAddEditComponent } from "../vault/app/vault/folder-add-edit.component";
@@ -150,9 +152,28 @@ export class AppComponent implements OnInit, OnDestroy {
private dialogService: DialogService, private dialogService: DialogService,
private biometricStateService: BiometricStateService, private biometricStateService: BiometricStateService,
private stateEventRunnerService: StateEventRunnerService, private stateEventRunnerService: StateEventRunnerService,
private providerService: ProviderService,
private accountService: AccountService, private accountService: AccountService,
) {} private sdkService: SdkService,
) {
if (flagEnabled("sdk")) {
// Warn if the SDK for some reason can't be initialized
this.sdkService.supported$
.pipe(
takeUntilDestroyed(),
catchError(() => {
return of(false);
}),
)
.subscribe((supported) => {
if (!supported) {
this.logService.debug("SDK is not supported");
this.sdkService.failedToInitialize().catch(this.logService.error);
} else {
this.logService.debug("SDK is supported");
}
});
}
}
ngOnInit() { ngOnInit() {
this.accountService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((account) => { this.accountService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((account) => {

View File

@@ -65,6 +65,7 @@ import {
} from "@bitwarden/common/platform/abstractions/log.service"; } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/platform/abstractions/system.service"; import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/platform/abstractions/system.service";
@@ -73,6 +74,8 @@ import { Message, MessageListener, MessageSender } from "@bitwarden/common/platf
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling"; import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling";
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory";
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { SystemService } from "@bitwarden/common/platform/services/system.service";
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage // eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
@@ -87,6 +90,7 @@ import { BiometricStateService, BiometricsService } from "@bitwarden/key-managem
import { DesktopLoginComponentService } from "../../auth/login/desktop-login-component.service"; import { DesktopLoginComponentService } from "../../auth/login/desktop-login-component.service";
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service"; import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
import { ElectronBiometricsService } from "../../key-management/biometrics/electron-biometrics.service"; import { ElectronBiometricsService } from "../../key-management/biometrics/electron-biometrics.service";
import { flagEnabled } from "../../platform/flags";
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service"; import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
import { ElectronCryptoService } from "../../platform/services/electron-crypto.service"; import { ElectronCryptoService } from "../../platform/services/electron-crypto.service";
import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service"; import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service";
@@ -332,6 +336,11 @@ const safeProviders: SafeProvider[] = [
useClass: LoginEmailService, useClass: LoginEmailService,
deps: [AccountService, AuthService, StateProvider], deps: [AccountService, AuthService, StateProvider],
}), }),
safeProvider({
provide: SdkClientFactory,
useClass: flagEnabled("sdk") ? DefaultSdkClientFactory : NoopSdkClientFactory,
deps: [],
}),
]; ];
@NgModule({ @NgModule({

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta <meta
http-equiv="Content-Security-Policy" http-equiv="Content-Security-Policy"
content="default-src 'self'; style-src 'self' 'unsafe-inline'; content="default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline';
img-src 'self' data: *; child-src *; frame-src *; connect-src *;" img-src 'self' data: *; child-src *; frame-src *; connect-src *;"
/> />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />

View File

@@ -331,7 +331,7 @@ export class NativeMessagingMain {
const ext = process.platform === "win32" ? ".exe" : ""; const ext = process.platform === "win32" ? ".exe" : "";
if (isDev()) { if (isDev()) {
return path.join( const devPath = path.join(
this.appPath, this.appPath,
"..", "..",
"desktop_native", "desktop_native",
@@ -339,6 +339,12 @@ export class NativeMessagingMain {
"debug", "debug",
`desktop_proxy${ext}`, `desktop_proxy${ext}`,
); );
// isDev() returns true when using a production build with ELECTRON_IS_DEV=1,
// so we need to fall back to the prod binary if the dev binary doesn't exist.
if (existsSync(devPath)) {
return devPath;
}
} }
return path.join(path.dirname(this.exePath), `desktop_proxy${ext}`); return path.join(path.dirname(this.exePath), `desktop_proxy${ext}`);

View File

@@ -1,26 +1,18 @@
{ {
"name": "@bitwarden/desktop", "name": "@bitwarden/desktop",
"version": "2024.9.2", "version": "2024.10.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@bitwarden/desktop", "name": "@bitwarden/desktop",
"version": "2024.9.2", "version": "2024.10.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@bitwarden/desktop-napi": "file:../desktop_native/napi", "@bitwarden/desktop-napi": "file:../desktop_native/napi",
"argon2": "0.40.1" "argon2": "0.40.1"
} }
}, },
"../desktop_native/napi": {
"name": "@bitwarden/desktop-napi",
"version": "0.1.0",
"license": "GPL-3.0",
"devDependencies": {
"@napi-rs/cli": "2.16.2"
}
},
"../desktop_native/napi": { "../desktop_native/napi": {
"version": "0.1.0", "version": "0.1.0",
"license": "GPL-3.0", "license": "GPL-3.0",

View File

@@ -2,7 +2,7 @@
"name": "@bitwarden/desktop", "name": "@bitwarden/desktop",
"productName": "Bitwarden", "productName": "Bitwarden",
"description": "A secure and free password manager for all of your devices.", "description": "A secure and free password manager for all of your devices.",
"version": "2024.9.2", "version": "2024.10.0",
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)", "author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
"homepage": "https://bitwarden.com", "homepage": "https://bitwarden.com",
"license": "GPL-3.0", "license": "GPL-3.0",

View File

@@ -42,7 +42,7 @@ const common = {
type: "asset/resource", type: "asset/resource",
}, },
{ {
test: /\.wasm$/, test: /argon2(-simd)?\.wasm$/,
loader: "base64-loader", loader: "base64-loader",
type: "javascript/auto", type: "javascript/auto",
}, },
@@ -143,11 +143,15 @@ const renderer = {
parser: { system: true }, parser: { system: true },
}, },
{ {
test: /\.wasm$/, test: /argon2(-simd)?\.wasm$/,
loader: "base64-loader", loader: "base64-loader",
type: "javascript/auto", type: "javascript/auto",
}, },
], ],
noParse: /argon2(-simd)?\.wasm$/,
},
experiments: {
asyncWebAssembly: true,
}, },
plugins: [ plugins: [
new AngularWebpackPlugin({ new AngularWebpackPlugin({

View File

@@ -11,6 +11,8 @@
"allowedHosts": "auto" "allowedHosts": "auto"
}, },
"flags": { "flags": {
"showPasswordless": false "showPasswordless": false,
} "sdk": true
},
"devFlags": {}
} }

View File

@@ -9,11 +9,19 @@ module.exports = {
...sharedConfig, ...sharedConfig,
preset: "jest-preset-angular", preset: "jest-preset-angular",
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"], setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper( moduleNameMapper: {
// Replace ESM SDK with Node compatible SDK
"@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
"<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
...pathsToModuleNameMapper(
{
// lets us use @bitwarden/common/spec in web tests // lets us use @bitwarden/common/spec in web tests
{ "@bitwarden/common/spec": ["../../libs/common/spec"], ...(compilerOptions?.paths ?? {}) }, "@bitwarden/common/spec": ["../../libs/common/spec"],
...(compilerOptions?.paths ?? {}),
},
{ {
prefix: "<rootDir>/", prefix: "<rootDir>/",
}, },
), ),
},
}; };

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bitwarden/web-vault", "name": "@bitwarden/web-vault",
"version": "2024.10.0", "version": "2024.10.1",
"scripts": { "scripts": {
"build:oss": "webpack", "build:oss": "webpack",
"build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",

View File

@@ -1,8 +1,9 @@
import { DOCUMENT } from "@angular/common"; import { DOCUMENT } from "@angular/common";
import { Component, Inject, NgZone, OnDestroy, OnInit } from "@angular/core"; import { Component, Inject, NgZone, OnDestroy, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { NavigationEnd, Router } from "@angular/router"; import { NavigationEnd, Router } from "@angular/router";
import * as jq from "jquery"; import * as jq from "jquery";
import { Subject, filter, firstValueFrom, map, takeUntil, timeout } from "rxjs"; import { Subject, filter, firstValueFrom, map, takeUntil, timeout, catchError, of } from "rxjs";
import { LogoutReason } from "@bitwarden/auth/common"; import { LogoutReason } from "@bitwarden/auth/common";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
@@ -19,7 +20,9 @@ import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broa
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { StateEventRunnerService } from "@bitwarden/common/platform/state"; import { StateEventRunnerService } from "@bitwarden/common/platform/state";
import { SyncService } from "@bitwarden/common/platform/sync"; import { SyncService } from "@bitwarden/common/platform/sync";
@@ -30,6 +33,8 @@ import { DialogService, ToastOptions, ToastService } from "@bitwarden/components
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { BiometricStateService } from "@bitwarden/key-management"; import { BiometricStateService } from "@bitwarden/key-management";
import { flagEnabled } from "../utils/flags";
import { PolicyListService } from "./admin-console/core/policy-list.service"; import { PolicyListService } from "./admin-console/core/policy-list.service";
import { import {
DisableSendPolicy, DisableSendPolicy,
@@ -85,7 +90,28 @@ export class AppComponent implements OnDestroy, OnInit {
private stateEventRunnerService: StateEventRunnerService, private stateEventRunnerService: StateEventRunnerService,
private organizationService: InternalOrganizationServiceAbstraction, private organizationService: InternalOrganizationServiceAbstraction,
private accountService: AccountService, private accountService: AccountService,
) {} private logService: LogService,
private sdkService: SdkService,
) {
if (flagEnabled("sdk")) {
// Warn if the SDK for some reason can't be initialized
this.sdkService.supported$
.pipe(
takeUntilDestroyed(),
catchError(() => {
return of(false);
}),
)
.subscribe((supported) => {
if (!supported) {
this.logService.debug("SDK is not supported");
this.sdkService.failedToInitialize().catch(this.logService.error);
} else {
this.logService.debug("SDK is supported");
}
});
}
}
ngOnInit() { ngOnInit() {
this.i18nService.locale$.pipe(takeUntil(this.destroy$)).subscribe((locale) => { this.i18nService.locale$.pipe(takeUntil(this.destroy$)).subscribe((locale) => {

View File

@@ -58,6 +58,7 @@ import { FileDownloadService } from "@bitwarden/common/platform/abstractions/fil
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { ThemeType } from "@bitwarden/common/platform/enums"; import { ThemeType } from "@bitwarden/common/platform/enums";
import { AppIdService as DefaultAppIdService } from "@bitwarden/common/platform/services/app-id.service"; import { AppIdService as DefaultAppIdService } from "@bitwarden/common/platform/services/app-id.service";
@@ -65,6 +66,7 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage // eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */ /* eslint-disable import/no-restricted-paths -- Implementation for memory storage */
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
@@ -80,6 +82,7 @@ import { CollectionService } from "@bitwarden/common/vault/abstractions/collecti
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import { BiometricsService } from "@bitwarden/key-management"; import { BiometricsService } from "@bitwarden/key-management";
import { flagEnabled } from "../../utils/flags";
import { PolicyListService } from "../admin-console/core/policy-list.service"; import { PolicyListService } from "../admin-console/core/policy-list.service";
import { import {
WebSetPasswordJitService, WebSetPasswordJitService,
@@ -93,6 +96,7 @@ import { I18nService } from "../core/i18n.service";
import { WebBiometricsService } from "../key-management/web-biometric.service"; import { WebBiometricsService } from "../key-management/web-biometric.service";
import { WebEnvironmentService } from "../platform/web-environment.service"; import { WebEnvironmentService } from "../platform/web-environment.service";
import { WebMigrationRunner } from "../platform/web-migration-runner"; import { WebMigrationRunner } from "../platform/web-migration-runner";
import { WebSdkClientFactory } from "../platform/web-sdk-client-factory";
import { WebStorageServiceProvider } from "../platform/web-storage-service.provider"; import { WebStorageServiceProvider } from "../platform/web-storage-service.provider";
import { EventService } from "./event.service"; import { EventService } from "./event.service";
@@ -270,6 +274,11 @@ const safeProviders: SafeProvider[] = [
useClass: DefaultCollectionAdminService, useClass: DefaultCollectionAdminService,
deps: [ApiService, CryptoServiceAbstraction, EncryptService, CollectionService], deps: [ApiService, CryptoServiceAbstraction, EncryptService, CollectionService],
}), }),
safeProvider({
provide: SdkClientFactory,
useClass: flagEnabled("sdk") ? WebSdkClientFactory : NoopSdkClientFactory,
deps: [],
}),
]; ];
@NgModule({ @NgModule({

View File

@@ -0,0 +1,42 @@
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import * as sdk from "@bitwarden/sdk-internal";
/**
* SDK client factory with a js fallback for when WASM is not supported.
*/
export class WebSdkClientFactory implements SdkClientFactory {
async createSdkClient(
...args: ConstructorParameters<typeof sdk.BitwardenClient>
): Promise<sdk.BitwardenClient> {
const module = await load();
(sdk as any).init(module);
return Promise.resolve(new sdk.BitwardenClient(...args));
}
}
// https://stackoverflow.com/a/47880734
const supported = (() => {
try {
if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
const module = new WebAssembly.Module(
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00),
);
if (module instanceof WebAssembly.Module) {
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
}
}
} catch (e) {
// ignore
}
return false;
})();
async function load() {
if (supported) {
return await import("@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm");
} else {
return await import("@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm.js");
}
}

View File

@@ -65,7 +65,7 @@
> >
{{ "cancel" | i18n }} {{ "cancel" | i18n }}
</button> </button>
<div class="tw-ml-auto"> <div class="tw-ml-auto" *ngIf="showDelete">
<button <button
bitIconButton="bwi-trash" bitIconButton="bwi-trash"
type="button" type="button"
@@ -73,6 +73,7 @@
[appA11yTitle]="'delete' | i18n" [appA11yTitle]="'delete' | i18n"
[bitAction]="delete" [bitAction]="delete"
[disabled]="!canDelete" [disabled]="!canDelete"
data-testid="delete-cipher-btn"
></button> ></button>
</div> </div>
</ng-container> </ng-container>

View File

@@ -179,6 +179,15 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
return this.cipher?.edit ?? false; return this.cipher?.edit ?? false;
} }
protected get showDelete() {
// Don't show the delete button when cloning a cipher
if (this.params.mode == "form" && this.formConfig.mode === "clone") {
return false;
}
// Never show the delete button for new ciphers
return this.cipher != null;
}
protected get showCipherView() { protected get showCipherView() {
return this.cipher != undefined && (this.params.mode === "view" || this.loadingForm); return this.cipher != undefined && (this.params.mode === "view" || this.loadingForm);
} }
@@ -332,8 +341,8 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
}; };
cancel = async () => { cancel = async () => {
// We're in View mode, or we don't have a cipher, close the dialog. // We're in View mode, we don't have a cipher, or we were cloning, close the dialog.
if (this.params.mode === "view" || this.cipher == null) { if (this.params.mode === "view" || this.cipher == null || this.formConfig.mode === "clone") {
this.dialogRef.close(this._cipherModified ? VaultItemDialogResult.Saved : undefined); this.dialogRef.close(this._cipherModified ? VaultItemDialogResult.Saved : undefined);
return; return;
} }

View File

@@ -0,0 +1,119 @@
import { TestBed } from "@angular/core/testing";
import { BehaviorSubject } from "rxjs";
import { CollectionAdminService } from "@bitwarden/admin-console/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CipherId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
import { AdminConsoleCipherFormConfigService } from "./admin-console-cipher-form-config.service";
describe("AdminConsoleCipherFormConfigService", () => {
let adminConsoleConfigService: AdminConsoleCipherFormConfigService;
const cipherId = "333-444-555" as CipherId;
const testOrg = { id: "333-44-55", name: "Test Org", canEditAllCiphers: false };
const organization$ = new BehaviorSubject<Organization>(testOrg as Organization);
const getCipherAdmin = jest.fn().mockResolvedValue(null);
const getCipher = jest.fn().mockResolvedValue(null);
beforeEach(async () => {
getCipherAdmin.mockClear();
getCipher.mockClear();
getCipher.mockResolvedValue({ id: cipherId, name: "Test Cipher - (non-admin)" });
getCipherAdmin.mockResolvedValue({ id: cipherId, name: "Test Cipher - (admin)" });
await TestBed.configureTestingModule({
providers: [
AdminConsoleCipherFormConfigService,
{ provide: OrganizationService, useValue: { get$: () => organization$ } },
{ provide: CipherService, useValue: { get: getCipher } },
{ provide: CollectionAdminService, useValue: { getAll: () => Promise.resolve([]) } },
{
provide: RoutedVaultFilterService,
useValue: { filter$: new BehaviorSubject({ organizationId: testOrg.id }) },
},
{ provide: ApiService, useValue: { getCipherAdmin } },
],
});
});
describe("buildConfig", () => {
it("sets individual attributes", async () => {
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
const { folders, hideIndividualVaultFields } = await adminConsoleConfigService.buildConfig(
"add",
cipherId,
);
expect(folders).toEqual([]);
expect(hideIndividualVaultFields).toBe(true);
});
it("sets mode based on passed mode", async () => {
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
const { mode } = await adminConsoleConfigService.buildConfig("edit", cipherId);
expect(mode).toBe("edit");
});
it("sets admin flag based on `canEditAllCiphers`", async () => {
// Disable edit all ciphers on org
testOrg.canEditAllCiphers = false;
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
let result = await adminConsoleConfigService.buildConfig("add", cipherId);
expect(result.admin).toBe(false);
// Enable edit all ciphers on org
testOrg.canEditAllCiphers = true;
result = await adminConsoleConfigService.buildConfig("add", cipherId);
expect(result.admin).toBe(true);
});
it("sets `allowPersonalOwnership` to false", async () => {
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
const result = await adminConsoleConfigService.buildConfig("clone", cipherId);
expect(result.allowPersonalOwnership).toBe(false);
});
describe("getCipher", () => {
it("retrieves the cipher from the cipher service", async () => {
testOrg.canEditAllCiphers = false;
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
const result = await adminConsoleConfigService.buildConfig("clone", cipherId);
expect(getCipher).toHaveBeenCalledWith(cipherId);
expect(result.originalCipher.name).toBe("Test Cipher - (non-admin)");
// Admin service not needed when cipher service can return the cipher
expect(getCipherAdmin).not.toHaveBeenCalled();
});
it("retrieves the cipher from the admin service", async () => {
getCipher.mockResolvedValueOnce(null);
getCipherAdmin.mockResolvedValue({ id: cipherId, name: "Test Cipher - (admin)" });
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
await adminConsoleConfigService.buildConfig("add", cipherId);
expect(getCipherAdmin).toHaveBeenCalledWith(cipherId);
expect(getCipher).toHaveBeenCalledWith(cipherId);
});
});
});
});

View File

@@ -0,0 +1,99 @@
import { inject, Injectable } from "@angular/core";
import { combineLatest, filter, firstValueFrom, map, switchMap } from "rxjs";
import { CollectionAdminService } from "@bitwarden/admin-console/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CipherId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherType } from "@bitwarden/common/vault/enums";
import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import {
CipherFormConfig,
CipherFormConfigService,
CipherFormMode,
} from "../../../../../../../libs/vault/src/cipher-form/abstractions/cipher-form-config.service";
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
/** Admin Console implementation of the `CipherFormConfigService`. */
@Injectable()
export class AdminConsoleCipherFormConfigService implements CipherFormConfigService {
private organizationService: OrganizationService = inject(OrganizationService);
private cipherService: CipherService = inject(CipherService);
private routedVaultFilterService: RoutedVaultFilterService = inject(RoutedVaultFilterService);
private collectionAdminService: CollectionAdminService = inject(CollectionAdminService);
private apiService: ApiService = inject(ApiService);
private organizationId$ = this.routedVaultFilterService.filter$.pipe(
map((filter) => filter.organizationId),
filter((filter) => filter !== undefined),
);
private organization$ = this.organizationId$.pipe(
switchMap((organizationId) => this.organizationService.get$(organizationId)),
);
private editableCollections$ = this.organization$.pipe(
switchMap(async (org) => {
const collections = await this.collectionAdminService.getAll(org.id);
// Users that can edit all ciphers can implicitly add to / edit within any collection
if (org.canEditAllCiphers) {
return collections;
}
// The user is only allowed to add/edit items to assigned collections that are not readonly
return collections.filter((c) => c.assigned && !c.readOnly);
}),
);
async buildConfig(
mode: CipherFormMode,
cipherId?: CipherId,
cipherType?: CipherType,
): Promise<CipherFormConfig> {
const [organization, allCollections] = await firstValueFrom(
combineLatest([this.organization$, this.editableCollections$]),
);
const cipher = await this.getCipher(organization, cipherId);
const collections = allCollections.filter(
(c) => c.organizationId === organization.id && c.assigned && !c.readOnly,
);
return {
mode,
cipherType: cipher?.type ?? cipherType ?? CipherType.Login,
admin: organization.canEditAllCiphers ?? false,
allowPersonalOwnership: false,
originalCipher: cipher,
collections,
organizations: [organization], // only a single org is in context at a time
folders: [], // folders not applicable in the admin console
hideIndividualVaultFields: true,
};
}
private async getCipher(organization: Organization, id?: CipherId): Promise<Cipher | null> {
if (id == null) {
return Promise.resolve(null);
}
// Check to see if the user has direct access to the cipher
const cipherFromCipherService = await this.cipherService.get(id);
// If the organization doesn't allow admin/owners to edit all ciphers return the cipher
if (!organization.canEditAllCiphers && cipherFromCipherService != null) {
return cipherFromCipherService;
}
// Retrieve the cipher through the means of an admin
const cipherResponse = await this.apiService.getCipherAdmin(id);
cipherResponse.edit = true;
const cipherData = new CipherData(cipherResponse);
return new Cipher(cipherData);
}
}

View File

@@ -1,3 +1,4 @@
import { DialogRef } from "@angular/cdk/dialog";
import { import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
@@ -42,16 +43,17 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SyncService } from "@bitwarden/common/platform/sync"; import { SyncService } from "@bitwarden/common/platform/sync";
import { OrganizationId } from "@bitwarden/common/types/guid"; import { CipherId, CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
@@ -62,7 +64,12 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
import { ServiceUtils } from "@bitwarden/common/vault/service-utils"; import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
import { DialogService, Icons, NoItemsModule, ToastService } from "@bitwarden/components"; import { DialogService, Icons, NoItemsModule, ToastService } from "@bitwarden/components";
import { CollectionAssignmentResult, PasswordRepromptService } from "@bitwarden/vault"; import {
CipherFormConfig,
CipherFormConfigService,
CollectionAssignmentResult,
PasswordRepromptService,
} from "@bitwarden/vault";
import { GroupService, GroupView } from "../../admin-console/organizations/core"; import { GroupService, GroupView } from "../../admin-console/organizations/core";
import { openEntityEventsDialog } from "../../admin-console/organizations/manage/entity-events.component"; import { openEntityEventsDialog } from "../../admin-console/organizations/manage/entity-events.component";
@@ -75,6 +82,11 @@ import {
CollectionDialogTabType, CollectionDialogTabType,
openCollectionDialog, openCollectionDialog,
} from "../components/collection-dialog"; } from "../components/collection-dialog";
import {
VaultItemDialogComponent,
VaultItemDialogMode,
VaultItemDialogResult,
} from "../components/vault-item-dialog/vault-item-dialog.component";
import { VaultItemEvent } from "../components/vault-items/vault-item-event"; import { VaultItemEvent } from "../components/vault-items/vault-item-event";
import { VaultItemsModule } from "../components/vault-items/vault-items.module"; import { VaultItemsModule } from "../components/vault-items/vault-items.module";
import { import {
@@ -89,12 +101,6 @@ import {
All, All,
RoutedVaultFilterModel, RoutedVaultFilterModel,
} from "../individual-vault/vault-filter/shared/models/routed-vault-filter.model"; } from "../individual-vault/vault-filter/shared/models/routed-vault-filter.model";
import {
openViewCipherDialog,
ViewCipherDialogCloseResult,
ViewCipherDialogResult,
ViewComponent,
} from "../individual-vault/view.component";
import { VaultHeaderComponent } from "../org-vault/vault-header/vault-header.component"; import { VaultHeaderComponent } from "../org-vault/vault-header/vault-header.component";
import { getNestedCollectionTree } from "../utils/collection-utils"; import { getNestedCollectionTree } from "../utils/collection-utils";
@@ -106,8 +112,8 @@ import {
} from "./bulk-collections-dialog"; } from "./bulk-collections-dialog";
import { CollectionAccessRestrictedComponent } from "./collection-access-restricted.component"; import { CollectionAccessRestrictedComponent } from "./collection-access-restricted.component";
import { openOrgVaultCollectionsDialog } from "./collections.component"; import { openOrgVaultCollectionsDialog } from "./collections.component";
import { AdminConsoleCipherFormConfigService } from "./services/admin-console-cipher-form-config.service";
import { VaultFilterModule } from "./vault-filter/vault-filter.module"; import { VaultFilterModule } from "./vault-filter/vault-filter.module";
const BroadcasterSubscriptionId = "OrgVaultComponent"; const BroadcasterSubscriptionId = "OrgVaultComponent";
const SearchTextDebounceInterval = 200; const SearchTextDebounceInterval = 200;
@@ -127,9 +133,12 @@ enum AddAccessStatusType {
VaultItemsModule, VaultItemsModule,
SharedModule, SharedModule,
NoItemsModule, NoItemsModule,
ViewComponent,
], ],
providers: [RoutedVaultFilterService, RoutedVaultFilterBridgeService], providers: [
RoutedVaultFilterService,
RoutedVaultFilterBridgeService,
{ provide: CipherFormConfigService, useClass: AdminConsoleCipherFormConfigService },
],
}) })
export class VaultComponent implements OnInit, OnDestroy { export class VaultComponent implements OnInit, OnDestroy {
protected Unassigned = Unassigned; protected Unassigned = Unassigned;
@@ -174,6 +183,8 @@ export class VaultComponent implements OnInit, OnDestroy {
private refresh$ = new BehaviorSubject<void>(null); private refresh$ = new BehaviorSubject<void>(null);
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
protected addAccessStatus$ = new BehaviorSubject<AddAccessStatusType>(0); protected addAccessStatus$ = new BehaviorSubject<AddAccessStatusType>(0);
private extensionRefreshEnabled: boolean;
private vaultItemDialogRef?: DialogRef<VaultItemDialogResult> | undefined;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -203,10 +214,15 @@ export class VaultComponent implements OnInit, OnDestroy {
private apiService: ApiService, private apiService: ApiService,
private collectionService: CollectionService, private collectionService: CollectionService,
private toastService: ToastService, private toastService: ToastService,
private accountService: AccountService, private configService: ConfigService,
private cipherFormConfigService: CipherFormConfigService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
this.extensionRefreshEnabled = await this.configService.getFeatureFlag(
FeatureFlag.ExtensionRefresh,
);
this.trashCleanupWarning = this.i18nService.t( this.trashCleanupWarning = this.i18nService.t(
this.platformUtilsService.isSelfHost() this.platformUtilsService.isSelfHost()
? "trashCleanupWarningSelfHosted" ? "trashCleanupWarningSelfHosted"
@@ -466,22 +482,27 @@ export class VaultComponent implements OnInit, OnDestroy {
firstSetup$ firstSetup$
.pipe( .pipe(
switchMap(() => this.route.queryParams), switchMap(() => this.route.queryParams),
// Only process the queryParams if the dialog is not open (only when extension refresh is enabled)
filter(() => this.vaultItemDialogRef == undefined || !this.extensionRefreshEnabled),
withLatestFrom(allCipherMap$, allCollections$, organization$), withLatestFrom(allCipherMap$, allCollections$, organization$),
switchMap(async ([qParams, allCiphersMap, allCollections]) => { switchMap(async ([qParams, allCiphersMap]) => {
const cipherId = getCipherIdFromParams(qParams); const cipherId = getCipherIdFromParams(qParams);
if (!cipherId) { if (!cipherId) {
return; return;
} }
const cipher = allCiphersMap[cipherId]; const cipher = allCiphersMap[cipherId];
const cipherCollections = allCollections.filter((c) =>
cipher.collectionIds.includes(c.id),
);
if (cipher) { if (cipher) {
if (qParams.action === "view") { let action = qParams.action;
await this.viewCipher(cipher, cipherCollections); // Default to "view" if extension refresh is enabled
if (action == null && this.extensionRefreshEnabled) {
action = "view";
}
if (action === "view") {
await this.viewCipherById(cipher);
} else { } else {
await this.editCipherId(cipherId); await this.editCipherId(cipher, false);
} }
} else { } else {
this.toastService.showToast({ this.toastService.showToast({
@@ -730,12 +751,16 @@ export class VaultComponent implements OnInit, OnDestroy {
} }
async addCipher(cipherType?: CipherType) { async addCipher(cipherType?: CipherType) {
if (this.extensionRefreshEnabled) {
return this.addCipherV2(cipherType);
}
let collections: CollectionView[] = []; let collections: CollectionView[] = [];
// Admins limited to only adding items to collections they have access to. // Admins limited to only adding items to collections they have access to.
collections = await firstValueFrom(this.editableCollections$); collections = await firstValueFrom(this.editableCollections$);
await this.editCipher(null, (comp) => { await this.editCipher(null, false, (comp) => {
comp.type = cipherType || this.activeFilter.cipherType; comp.type = cipherType || this.activeFilter.cipherType;
comp.collections = collections; comp.collections = collections;
if (this.activeFilter.collectionId) { if (this.activeFilter.collectionId) {
@@ -744,20 +769,46 @@ export class VaultComponent implements OnInit, OnDestroy {
}); });
} }
/** Opens the Add/Edit Dialog. Only to be used when the BrowserExtension feature flag is active */
async addCipherV2(cipherType?: CipherType) {
const cipherFormConfig = await this.cipherFormConfigService.buildConfig(
"add",
null,
cipherType,
);
const collectionId: CollectionId | undefined = this.activeFilter.collectionId as CollectionId;
cipherFormConfig.initialValues = {
organizationId: this.organization.id as OrganizationId,
collectionIds: collectionId ? [collectionId] : [],
};
await this.openVaultItemDialog("form", cipherFormConfig);
}
/**
* Edit the given cipher
* @param cipherView - The cipher to be edited
* @param cloneCipher - `true` when the cipher should be cloned.
* Used in place of the `additionalComponentParameters`, as
* the `editCipherIdV2` method has a differing implementation.
* @param defaultComponentParameters - A method that takes in an instance of
* the `AddEditComponent` to edit methods directly.
*/
async editCipher( async editCipher(
cipher: CipherView, cipher: CipherView,
cloneCipher: boolean,
additionalComponentParameters?: (comp: AddEditComponent) => void, additionalComponentParameters?: (comp: AddEditComponent) => void,
) { ) {
return this.editCipherId(cipher?.id, additionalComponentParameters); return this.editCipherId(cipher, cloneCipher, additionalComponentParameters);
} }
async editCipherId( async editCipherId(
cipherId: string, cipher: CipherView,
cloneCipher: boolean,
additionalComponentParameters?: (comp: AddEditComponent) => void, additionalComponentParameters?: (comp: AddEditComponent) => void,
) { ) {
const cipher = await this.cipherService.get(cipherId);
// if cipher exists (cipher is null when new) and MP reprompt
// is on for this cipher, then show password reprompt
if ( if (
cipher && cipher &&
cipher.reprompt !== 0 && cipher.reprompt !== 0 &&
@@ -768,10 +819,15 @@ export class VaultComponent implements OnInit, OnDestroy {
return; return;
} }
if (this.extensionRefreshEnabled) {
await this.editCipherIdV2(cipher, cloneCipher);
return;
}
const defaultComponentParameters = (comp: AddEditComponent) => { const defaultComponentParameters = (comp: AddEditComponent) => {
comp.organization = this.organization; comp.organization = this.organization;
comp.organizationId = this.organization.id; comp.organizationId = this.organization.id;
comp.cipherId = cipherId; comp.cipherId = cipher.id;
comp.onSavedCipher.pipe(takeUntil(this.destroy$)).subscribe(() => { comp.onSavedCipher.pipe(takeUntil(this.destroy$)).subscribe(() => {
modal.close(); modal.close();
this.refresh(); this.refresh();
@@ -807,46 +863,70 @@ export class VaultComponent implements OnInit, OnDestroy {
} }
/** /**
* Takes a cipher and its assigned collections to opens dialog where it can be viewed. * Edit a cipher using the new AddEditCipherDialogV2 component.
* @param cipher - the cipher to view * Only to be used behind the ExtensionRefresh feature flag.
* @param collections - the collections the cipher is assigned to
*/ */
async viewCipher(cipher: CipherView, collections: CollectionView[] = []) { private async editCipherIdV2(cipher: CipherView, cloneCipher: boolean) {
const cipherFormConfig = await this.cipherFormConfigService.buildConfig(
cloneCipher ? "clone" : "edit",
cipher.id as CipherId,
);
await this.openVaultItemDialog("form", cipherFormConfig, cipher);
}
/** Opens the view dialog for the given cipher unless password reprompt fails */
async viewCipherById(cipher: CipherView) {
if (!cipher) { if (!cipher) {
this.go({ cipherId: null, itemId: null });
return; return;
} }
if (cipher.reprompt !== 0 && !(await this.passwordRepromptService.showPasswordPrompt())) { if (
// didn't pass password prompt, so don't open the dialog cipher &&
this.go({ cipherId: null, itemId: null }); cipher.reprompt !== 0 &&
!(await this.passwordRepromptService.showPasswordPrompt())
) {
// Didn't pass password prompt, so don't open add / edit modal.
await this.go({ cipherId: null, itemId: null, action: null });
return; return;
} }
const dialogRef = openViewCipherDialog(this.dialogService, { const cipherFormConfig = await this.cipherFormConfigService.buildConfig(
data: { "edit",
cipher: cipher, cipher.id as CipherId,
collections: collections, cipher.type,
disableEdit: !cipher.edit && !this.organization.canEditAllCiphers, );
},
await this.openVaultItemDialog("view", cipherFormConfig, cipher);
}
/**
* Open the combined view / edit dialog for a cipher.
*/
async openVaultItemDialog(
mode: VaultItemDialogMode,
formConfig: CipherFormConfig,
cipher?: CipherView,
) {
const disableForm = cipher ? !cipher.edit && !this.organization.canEditAllCiphers : false;
// If the form is disabled, force the mode into `view`
const dialogMode = disableForm ? "view" : mode;
this.vaultItemDialogRef = VaultItemDialogComponent.open(this.dialogService, {
mode: dialogMode,
formConfig,
disableForm,
}); });
// Wait for the dialog to close. const result = await lastValueFrom(this.vaultItemDialogRef.closed);
const result: ViewCipherDialogCloseResult = await lastValueFrom(dialogRef.closed); this.vaultItemDialogRef = undefined;
// If the dialog was closed by clicking the edit button, navigate to open the edit dialog.
if (result?.action === ViewCipherDialogResult.Edited) {
this.go({ itemId: cipher.id, action: "edit" });
return;
}
// If the dialog was closed by deleting the cipher, refresh the vault. // If the dialog was closed by deleting the cipher, refresh the vault.
if (result?.action === ViewCipherDialogResult.Deleted) { if (result === VaultItemDialogResult.Deleted || result === VaultItemDialogResult.Saved) {
this.refresh(); this.refresh();
} }
// Clear the query params when the view dialog closes // Clear the query params when the dialog closes
this.go({ cipherId: null, itemId: null, action: null }); await this.go({ cipherId: null, itemId: null, action: null });
} }
async cloneCipher(cipher: CipherView) { async cloneCipher(cipher: CipherView) {
@@ -867,7 +947,7 @@ export class VaultComponent implements OnInit, OnDestroy {
// Admins limited to only adding items to collections they have access to. // Admins limited to only adding items to collections they have access to.
collections = await firstValueFrom(this.editableCollections$); collections = await firstValueFrom(this.editableCollections$);
await this.editCipher(cipher, (comp) => { await this.editCipher(cipher, true, (comp) => {
comp.cloneMode = true; comp.cloneMode = true;
comp.collections = collections; comp.collections = collections;
comp.collectionIds = cipher.collectionIds; comp.collectionIds = cipher.collectionIds;

View File

@@ -78,7 +78,7 @@ const moduleRules = [
loader: "@ngtools/webpack", loader: "@ngtools/webpack",
}, },
{ {
test: /\.wasm$/, test: /argon2(-simd)?\.wasm$/,
loader: "base64-loader", loader: "base64-loader",
type: "javascript/auto", type: "javascript/auto",
}, },
@@ -324,6 +324,7 @@ const webpackConfig = {
mode: NODE_ENV, mode: NODE_ENV,
devtool: "source-map", devtool: "source-map",
devServer: devServer, devServer: devServer,
target: "web",
entry: { entry: {
"app/polyfills": "./src/polyfills.ts", "app/polyfills": "./src/polyfills.ts",
"app/main": "./src/main.ts", "app/main": "./src/main.ts",
@@ -383,9 +384,12 @@ const webpackConfig = {
clean: true, clean: true,
}, },
module: { module: {
noParse: /\.wasm$/, noParse: /argon2(-simd)?\.wasm$/,
rules: moduleRules, rules: moduleRules,
}, },
experiments: {
asyncWebAssembly: true,
},
plugins: plugins, plugins: plugins,
}; };

View File

@@ -10,7 +10,11 @@ module.exports = {
preset: "ts-jest", preset: "ts-jest",
testEnvironment: "node", testEnvironment: "node",
setupFilesAfterEnv: ["<rootDir>/../../apps/cli/test.setup.ts"], setupFilesAfterEnv: ["<rootDir>/../../apps/cli/test.setup.ts"],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { moduleNameMapper: {
"@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
"<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
...pathsToModuleNameMapper(compilerOptions?.paths || {}, {
prefix: "<rootDir>/", prefix: "<rootDir>/",
}), }),
},
}; };

View File

@@ -3,7 +3,7 @@
"pretty": true, "pretty": true,
"moduleResolution": "node", "moduleResolution": "node",
"target": "ES2016", "target": "ES2016",
"module": "es6", "module": "ES2020",
"noImplicitAny": true, "noImplicitAny": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,

View File

@@ -153,6 +153,8 @@ import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwar
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.service";
import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { ValidationService as ValidationServiceAbstraction } from "@bitwarden/common/platform/abstractions/validation.service"; import { ValidationService as ValidationServiceAbstraction } from "@bitwarden/common/platform/abstractions/validation.service";
@@ -181,6 +183,7 @@ import { KeyGenerationService } from "@bitwarden/common/platform/services/key-ge
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
import { NoopNotificationsService } from "@bitwarden/common/platform/services/noop-notifications.service"; import { NoopNotificationsService } from "@bitwarden/common/platform/services/noop-notifications.service";
import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/default-sdk.service";
import { StateService } from "@bitwarden/common/platform/services/state.service"; import { StateService } from "@bitwarden/common/platform/services/state.service";
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
@@ -1337,6 +1340,16 @@ const safeProviders: SafeProvider[] = [
SsoLoginServiceAbstraction, SsoLoginServiceAbstraction,
], ],
}), }),
safeProvider({
provide: SdkService,
useClass: DefaultSdkService,
deps: [
SdkClientFactory,
EnvironmentService,
PlatformUtilsServiceAbstraction,
ApiServiceAbstraction,
],
}),
]; ];
@NgModule({ @NgModule({

View File

@@ -605,6 +605,10 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.collections = this.writeableCollections?.filter( this.collections = this.writeableCollections?.filter(
(c) => c.organizationId === this.cipher.organizationId, (c) => c.organizationId === this.cipher.organizationId,
); );
// If there's only one collection, check it by default
if (this.collections.length === 1) {
(this.collections[0] as any).checked = true;
}
const org = await this.organizationService.get(this.cipher.organizationId); const org = await this.organizationService.get(this.cipher.organizationId);
if (org != null) { if (org != null) {
this.cipher.organizationUseTotp = org.useTotp; this.cipher.organizationUseTotp = org.useTotp;

View File

@@ -0,0 +1,9 @@
import { ClientSettings, LogLevel, BitwardenClient } from "@bitwarden/sdk-internal";
import { SdkClientFactory } from "../src/platform/abstractions/sdk/sdk-client-factory";
export class DefaultSdkClientFactory implements SdkClientFactory {
createSdkClient(settings?: ClientSettings, log_level?: LogLevel): Promise<BitwardenClient> {
throw new Error("Method not implemented.");
}
}

View File

@@ -0,0 +1,10 @@
import type { BitwardenClient } from "@bitwarden/sdk-internal";
/**
* Factory for creating SDK clients.
*/
export abstract class SdkClientFactory {
abstract createSdkClient(
...args: ConstructorParameters<typeof BitwardenClient>
): Promise<BitwardenClient>;
}

View File

@@ -0,0 +1,10 @@
import { Observable } from "rxjs";
import { BitwardenClient } from "@bitwarden/sdk-internal";
export abstract class SdkService {
client$: Observable<BitwardenClient>;
supported$: Observable<boolean>;
abstract failedToInitialize(): Promise<void>;
}

View File

@@ -2,6 +2,7 @@
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
export type SharedFlags = { export type SharedFlags = {
showPasswordless?: boolean; showPasswordless?: boolean;
sdk?: boolean;
}; };
// required to avoid linting errors when there are no flags // required to avoid linting errors when there are no flags
@@ -28,7 +29,7 @@ function getFlags<T>(envFlags: string | T): T {
* @returns The value of the flag * @returns The value of the flag
*/ */
export function flagEnabled<Flags extends SharedFlags>(flag: keyof Flags): boolean { export function flagEnabled<Flags extends SharedFlags>(flag: keyof Flags): boolean {
const flags = getFlags<Flags>(process.env.FLAGS); const flags = getFlags<Flags>(process.env.FLAGS) ?? ({} as Flags);
return flags[flag] == null || !!flags[flag]; return flags[flag] == null || !!flags[flag];
} }

View File

@@ -0,0 +1,19 @@
import * as sdk from "@bitwarden/sdk-internal";
import * as module from "@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm";
import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory";
/**
* Directly imports the Bitwarden SDK and initializes it.
*
* **Warning**: This requires WASM support and will fail if the environment does not support it.
*/
export class DefaultSdkClientFactory implements SdkClientFactory {
async createSdkClient(
...args: ConstructorParameters<typeof sdk.BitwardenClient>
): Promise<sdk.BitwardenClient> {
(sdk as any).init(module);
return Promise.resolve(new sdk.BitwardenClient(...args));
}
}

View File

@@ -0,0 +1,111 @@
import { concatMap, firstValueFrom, shareReplay } from "rxjs";
import { LogLevel, DeviceType as SdkDeviceType } from "@bitwarden/sdk-internal";
import { ApiService } from "../../../abstractions/api.service";
import { DeviceType } from "../../../enums/device-type.enum";
import { EnvironmentService } from "../../abstractions/environment.service";
import { PlatformUtilsService } from "../../abstractions/platform-utils.service";
import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory";
import { SdkService } from "../../abstractions/sdk/sdk.service";
export class DefaultSdkService implements SdkService {
client$ = this.environmentService.environment$.pipe(
concatMap(async (env) => {
const settings = {
apiUrl: env.getApiUrl(),
identityUrl: env.getIdentityUrl(),
deviceType: this.toDevice(this.platformUtilsService.getDevice()),
userAgent: this.userAgent ?? navigator.userAgent,
};
return await this.sdkClientFactory.createSdkClient(settings, LogLevel.Info);
}),
shareReplay({ refCount: true, bufferSize: 1 }),
);
supported$ = this.client$.pipe(
concatMap(async (client) => {
return client.echo("bitwarden wasm!") === "bitwarden wasm!";
}),
);
constructor(
private sdkClientFactory: SdkClientFactory,
private environmentService: EnvironmentService,
private platformUtilsService: PlatformUtilsService,
private apiService: ApiService, // Yes we shouldn't import ApiService, but it's temporary
private userAgent: string = null,
) {}
async failedToInitialize(): Promise<void> {
// Only log on cloud instances
if (
this.platformUtilsService.isDev() ||
!(await firstValueFrom(this.environmentService.environment$)).isCloud
) {
return;
}
return this.apiService.send("POST", "/wasm-debug", null, false, false, null, (headers) => {
headers.append("SDK-Version", "1.0.0");
});
}
private toDevice(device: DeviceType): SdkDeviceType {
switch (device) {
case DeviceType.Android:
return "Android";
case DeviceType.iOS:
return "iOS";
case DeviceType.ChromeExtension:
return "ChromeExtension";
case DeviceType.FirefoxExtension:
return "FirefoxExtension";
case DeviceType.OperaExtension:
return "OperaExtension";
case DeviceType.EdgeExtension:
return "EdgeExtension";
case DeviceType.WindowsDesktop:
return "WindowsDesktop";
case DeviceType.MacOsDesktop:
return "MacOsDesktop";
case DeviceType.LinuxDesktop:
return "LinuxDesktop";
case DeviceType.ChromeBrowser:
return "ChromeBrowser";
case DeviceType.FirefoxBrowser:
return "FirefoxBrowser";
case DeviceType.OperaBrowser:
return "OperaBrowser";
case DeviceType.EdgeBrowser:
return "EdgeBrowser";
case DeviceType.IEBrowser:
return "IEBrowser";
case DeviceType.UnknownBrowser:
return "UnknownBrowser";
case DeviceType.AndroidAmazon:
return "AndroidAmazon";
case DeviceType.UWP:
return "UWP";
case DeviceType.SafariBrowser:
return "SafariBrowser";
case DeviceType.VivaldiBrowser:
return "VivaldiBrowser";
case DeviceType.VivaldiExtension:
return "VivaldiExtension";
case DeviceType.SafariExtension:
return "SafariExtension";
case DeviceType.Server:
return "Server";
case DeviceType.WindowsCLI:
return "WindowsCLI";
case DeviceType.MacOsCLI:
return "MacOsCLI";
case DeviceType.LinuxCLI:
return "LinuxCLI";
default:
return "SDK";
}
}
}

View File

@@ -0,0 +1,16 @@
import type { BitwardenClient } from "@bitwarden/sdk-internal";
import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory";
/**
* Noop SDK client factory.
*
* Used during SDK rollout to prevent bundling the SDK with some applications.
*/
export class NoopSdkClientFactory implements SdkClientFactory {
createSdkClient(
...args: ConstructorParameters<typeof BitwardenClient>
): Promise<BitwardenClient> {
return Promise.reject(new Error("SDK not available"));
}
}

View File

@@ -8,6 +8,7 @@ import { TreeNode } from "../models/domain/tree-node";
import { CollectionView } from "../models/view/collection.view"; import { CollectionView } from "../models/view/collection.view";
export abstract class CollectionService { export abstract class CollectionService {
encryptedCollections$: Observable<Collection[]>;
decryptedCollections$: Observable<CollectionView[]>; decryptedCollections$: Observable<CollectionView[]>;
clearActiveUserCache: () => Promise<void>; clearActiveUserCache: () => Promise<void>;

View File

@@ -673,6 +673,8 @@ export class CipherService implements CipherServiceAbstraction {
if (orgAdmin && cipher.organizationId != null) { if (orgAdmin && cipher.organizationId != null) {
const request = new CipherCreateRequest(cipher); const request = new CipherCreateRequest(cipher);
response = await this.apiService.postCipherAdmin(request); response = await this.apiService.postCipherAdmin(request);
const data = new CipherData(response, cipher.collectionIds);
return new Cipher(data);
} else if (cipher.collectionIds != null) { } else if (cipher.collectionIds != null) {
const request = new CipherCreateRequest(cipher); const request = new CipherCreateRequest(cipher);
response = await this.apiService.postCipherCreate(request); response = await this.apiService.postCipherCreate(request);
@@ -697,6 +699,8 @@ export class CipherService implements CipherServiceAbstraction {
if (orgAdmin && isNotClone) { if (orgAdmin && isNotClone) {
const request = new CipherRequest(cipher); const request = new CipherRequest(cipher);
response = await this.apiService.putCipherAdmin(cipher.id, request); response = await this.apiService.putCipherAdmin(cipher.id, request);
const data = new CipherData(response, cipher.collectionIds);
return new Cipher(data, cipher.localData);
} else if (cipher.edit) { } else if (cipher.edit) {
const request = new CipherRequest(cipher); const request = new CipherRequest(cipher);
response = await this.apiService.putCipher(cipher.id, request); response = await this.apiService.putCipher(cipher.id, request);

View File

@@ -56,6 +56,16 @@ describe("1Password 1Pux Importer", () => {
const SecureNoteDataJson = JSON.stringify(SecureNoteData); const SecureNoteDataJson = JSON.stringify(SecureNoteData);
const SanitizedExportJson = JSON.stringify(SanitizedExport); const SanitizedExportJson = JSON.stringify(SanitizedExport);
it("should not import items with state 'archived'", async () => {
const importer = new OnePassword1PuxImporter();
const archivedLoginData = LoginData;
archivedLoginData["accounts"][0]["vaults"][0]["items"][0]["state"] = "archived";
const archivedDataJson = JSON.stringify(archivedLoginData);
const result = await importer.parse(archivedDataJson);
expect(result != null).toBe(true);
expect(result.ciphers.length).toBe(0);
});
it("should parse login data", async () => { it("should parse login data", async () => {
const importer = new OnePassword1PuxImporter(); const importer = new OnePassword1PuxImporter();
const result = await importer.parse(LoginDataJson); const result = await importer.parse(LoginDataJson);

View File

@@ -26,7 +26,7 @@ export const APICredentialsData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465969, createdAt: 1619465969,
updatedAt: 1619466052, updatedAt: 1619466052,
trashed: false, state: "active",
categoryUuid: "112", categoryUuid: "112",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
string: "apiuser@nullvalue.test", string: "apiuser@nullvalue.test",
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
concealed: "apiapiapiapiapiapiappy", concealed: "apiapiapiapiapiapiappy",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: true, dontGenerate: true,
@@ -73,7 +71,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
menu: "jwt", menu: "jwt",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
string: "filename.jwt", string: "filename.jwt",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
date: 1301918460, date: 1301918460,
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
date: 1932811260, date: 1932811260,
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const APICredentialsData: ExportData = {
value: { value: {
string: "not.your.everyday.hostname", string: "not.your.everyday.hostname",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const BankAccountData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619466056, createdAt: 1619466056,
updatedAt: 1619466187, updatedAt: 1619466187,
trashed: false, state: "active",
categoryUuid: "101", categoryUuid: "101",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "Super Credit Union", string: "Super Credit Union",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "Cool Guy", string: "Cool Guy",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const BankAccountData: ExportData = {
value: { value: {
menu: "checking", menu: "checking",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "111000999", string: "111000999",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "192837465918273645", string: "192837465918273645",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "123456", string: "123456",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "DE12 123456", string: "DE12 123456",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const BankAccountData: ExportData = {
value: { value: {
concealed: "5555", concealed: "5555",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: true, dontGenerate: true,
@@ -175,7 +167,6 @@ export const BankAccountData: ExportData = {
value: { value: {
phone: "9399399933", phone: "9399399933",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -191,7 +182,6 @@ export const BankAccountData: ExportData = {
value: { value: {
string: "1 Fifth Avenue", string: "1 Fifth Avenue",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const CreditCardData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465282, createdAt: 1619465282,
updatedAt: 1619465447, updatedAt: 1619465447,
trashed: false, state: "active",
categoryUuid: "002", categoryUuid: "002",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "Fred Engels", string: "Fred Engels",
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const CreditCardData: ExportData = {
value: { value: {
creditCardType: "discover", creditCardType: "discover",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const CreditCardData: ExportData = {
value: { value: {
creditCardNumber: "6011111111111117", creditCardNumber: "6011111111111117",
}, },
indexAtSource: 2,
guarded: true, guarded: true,
clipboardFilter: "0123456789", clipboardFilter: "0123456789",
multiline: false, multiline: false,
@@ -90,7 +87,6 @@ export const CreditCardData: ExportData = {
value: { value: {
concealed: "1312", concealed: "1312",
}, },
indexAtSource: 3,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: true, dontGenerate: true,
@@ -106,7 +102,6 @@ export const CreditCardData: ExportData = {
value: { value: {
monthYear: 209912, monthYear: 209912,
}, },
indexAtSource: 4,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -122,7 +117,6 @@ export const CreditCardData: ExportData = {
value: { value: {
monthYear: 200101, monthYear: 200101,
}, },
indexAtSource: 5,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -138,7 +132,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "card", string: "card",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -160,7 +153,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "Some bank", string: "Some bank",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -176,7 +168,6 @@ export const CreditCardData: ExportData = {
value: { value: {
phone: "123456", phone: "123456",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -192,7 +183,6 @@ export const CreditCardData: ExportData = {
value: { value: {
phone: "0800123456", phone: "0800123456",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -208,7 +198,6 @@ export const CreditCardData: ExportData = {
value: { value: {
phone: "+49123456", phone: "+49123456",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -224,7 +213,6 @@ export const CreditCardData: ExportData = {
value: { value: {
url: "somebank.com", url: "somebank.com",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -246,7 +234,6 @@ export const CreditCardData: ExportData = {
value: { value: {
concealed: "1234", concealed: "1234",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: true, dontGenerate: true,
@@ -262,7 +249,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "$1312", string: "$1312",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -278,7 +264,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "$500", string: "$500",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -294,7 +279,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "1%", string: "1%",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -310,7 +294,6 @@ export const CreditCardData: ExportData = {
value: { value: {
string: "123456", string: "123456",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const DatabaseData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619466193, createdAt: 1619466193,
updatedAt: 1619466276, updatedAt: 1619466276,
trashed: false, state: "active",
categoryUuid: "102", categoryUuid: "102",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const DatabaseData: ExportData = {
value: { value: {
menu: "postgresql", menu: "postgresql",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "my.secret.db.server", string: "my.secret.db.server",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "1337", string: "1337",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "user_database", string: "user_database",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "cooldbuser", string: "cooldbuser",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const DatabaseData: ExportData = {
value: { value: {
concealed: "^+kTjhLaN7wVPAhGU)*J", concealed: "^+kTjhLaN7wVPAhGU)*J",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "ASDIUFU-283234", string: "ASDIUFU-283234",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "cdbu", string: "cdbu",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -169,7 +161,6 @@ export const DatabaseData: ExportData = {
value: { value: {
string: "ssh", string: "ssh",
}, },
indexAtSource: 8,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const DriversLicenseData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619466279, createdAt: 1619466279,
updatedAt: 1619466425, updatedAt: 1619466425,
trashed: false, state: "active",
categoryUuid: "103", categoryUuid: "103",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "Michael Scarn", string: "Michael Scarn",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "2120 Mifflin Rd.", string: "2120 Mifflin Rd.",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
date: 252504060, date: 252504060,
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
gender: "male", gender: "male",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "5'11\"", string: "5'11\"",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "12345678901", string: "12345678901",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "C", string: "C",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "B", string: "B",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -169,7 +161,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "Pennsylvania", string: "Pennsylvania",
}, },
indexAtSource: 8,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -185,7 +176,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
string: "United States", string: "United States",
}, },
indexAtSource: 9,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -201,7 +191,6 @@ export const DriversLicenseData: ExportData = {
value: { value: {
monthYear: 203012, monthYear: 203012,
}, },
indexAtSource: 10,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const EmailAccountData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619466428, createdAt: 1619466428,
updatedAt: 1619466585, updatedAt: 1619466585,
trashed: false, state: "active",
categoryUuid: "111", categoryUuid: "111",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
menu: "either", menu: "either",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "someuser@nullvalue.test", string: "someuser@nullvalue.test",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "mailserver.nullvalue.test", string: "mailserver.nullvalue.test",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "587", string: "587",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
concealed: "u1jsf<UI*&YU&^T", concealed: "u1jsf<UI*&YU&^T",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
menu: "TLS", menu: "TLS",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
menu: "kerberos_v5", menu: "kerberos_v5",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -159,7 +152,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "mailserver.nullvalue.test", string: "mailserver.nullvalue.test",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -175,7 +167,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "589", string: "589",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -191,7 +182,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "someuser@nullvalue.test", string: "someuser@nullvalue.test",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -207,7 +197,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
concealed: "(*1674%^UIUJ*UI(IUI8u98uyy", concealed: "(*1674%^UIUJ*UI(IUI8u98uyy",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -223,7 +212,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
menu: "TLS", menu: "TLS",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -239,7 +227,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
menu: "password", menu: "password",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -261,7 +248,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "Telum", string: "Telum",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -277,7 +263,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "https://telum.nullvalue.test", string: "https://telum.nullvalue.test",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -293,7 +278,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "2346666666", string: "2346666666",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -309,7 +293,6 @@ export const EmailAccountData: ExportData = {
value: { value: {
string: "18005557777", string: "18005557777",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const EmailFieldOnIdentityData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465450, createdAt: 1619465450,
updatedAt: 1619465789, updatedAt: 1619465789,
trashed: false, state: "active",
categoryUuid: "004", categoryUuid: "004",
details: { details: {
loginFields: [], loginFields: [],
@@ -55,7 +55,6 @@ export const EmailFieldOnIdentityData: ExportData = {
provider: "myEmailProvider", provider: "myEmailProvider",
}, },
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const EmailFieldOnIdentityPrefilledData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465450, createdAt: 1619465450,
updatedAt: 1619465789, updatedAt: 1619465789,
trashed: false, state: "active",
categoryUuid: "004", categoryUuid: "004",
details: { details: {
loginFields: [], loginFields: [],
@@ -52,7 +52,6 @@ export const EmailFieldOnIdentityPrefilledData: ExportData = {
value: { value: {
string: "gengels@nullvalue.test", string: "gengels@nullvalue.test",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -71,7 +70,6 @@ export const EmailFieldOnIdentityPrefilledData: ExportData = {
provider: "myEmailProvider", provider: "myEmailProvider",
}, },
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const EmailFieldData: ExportData = {
favIndex: 1, favIndex: 1,
createdAt: 1619467985, createdAt: 1619467985,
updatedAt: 1619468230, updatedAt: 1619468230,
trashed: false, state: "active",
categoryUuid: "100", categoryUuid: "100",
details: { details: {
loginFields: [], loginFields: [],
@@ -49,7 +49,6 @@ export const EmailFieldData: ExportData = {
provider: "myEmailProvider", provider: "myEmailProvider",
}, },
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const IdentityData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465450, createdAt: 1619465450,
updatedAt: 1619465789, updatedAt: 1619465789,
trashed: false, state: "active",
categoryUuid: "004", categoryUuid: "004",
details: { details: {
loginFields: [], loginFields: [],
@@ -42,7 +42,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "George", string: "George",
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -58,7 +57,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "S", string: "S",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -74,7 +72,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Engels", string: "Engels",
}, },
indexAtSource: 2,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -90,7 +87,6 @@ export const IdentityData: ExportData = {
value: { value: {
menu: "male", menu: "male",
}, },
indexAtSource: 3,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -106,7 +102,6 @@ export const IdentityData: ExportData = {
value: { value: {
date: 347198460, date: 347198460,
}, },
indexAtSource: 4,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -122,7 +117,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Steel Worker", string: "Steel Worker",
}, },
indexAtSource: 5,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -138,7 +132,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Acme Inc.", string: "Acme Inc.",
}, },
indexAtSource: 6,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -154,7 +147,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "QA", string: "QA",
}, },
indexAtSource: 7,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -170,7 +162,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Quality Assurance Manager", string: "Quality Assurance Manager",
}, },
indexAtSource: 8,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -198,7 +189,6 @@ export const IdentityData: ExportData = {
state: "California", state: "California",
}, },
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -214,7 +204,6 @@ export const IdentityData: ExportData = {
value: { value: {
phone: "4565555555", phone: "4565555555",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -230,7 +219,6 @@ export const IdentityData: ExportData = {
value: { value: {
phone: "4575555555", phone: "4575555555",
}, },
indexAtSource: 2,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -246,7 +234,6 @@ export const IdentityData: ExportData = {
value: { value: {
phone: "4585555555", phone: "4585555555",
}, },
indexAtSource: 3,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -262,7 +249,6 @@ export const IdentityData: ExportData = {
value: { value: {
phone: "4595555555", phone: "4595555555",
}, },
indexAtSource: 4,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -284,7 +270,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "gengels", string: "gengels",
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -300,7 +285,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Who's a super cool guy?", string: "Who's a super cool guy?",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -316,7 +300,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "Me, buddy.", string: "Me, buddy.",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -332,7 +315,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "gengels@nullvalue.test", string: "gengels@nullvalue.test",
}, },
indexAtSource: 3,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -348,7 +330,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "cv.gengels.nullvalue.test", string: "cv.gengels.nullvalue.test",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -364,7 +345,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "12345678", string: "12345678",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -380,7 +360,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "skypeisbad1619", string: "skypeisbad1619",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -396,7 +375,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "aollol@lololol.aol.com", string: "aollol@lololol.aol.com",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -412,7 +390,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "sk8rboi13@yah00.com", string: "sk8rboi13@yah00.com",
}, },
indexAtSource: 8,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -428,7 +405,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "msnothankyou@msn&m&m.com", string: "msnothankyou@msn&m&m.com",
}, },
indexAtSource: 9,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -444,7 +420,6 @@ export const IdentityData: ExportData = {
value: { value: {
string: "super cool guy", string: "super cool guy",
}, },
indexAtSource: 10,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const LoginData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1635522833, createdAt: 1635522833,
updatedAt: 1635522872, updatedAt: 1635522872,
trashed: false, state: "active",
categoryUuid: "001", categoryUuid: "001",
details: { details: {
loginFields: [ loginFields: [
@@ -68,7 +68,6 @@ export const LoginData: ExportData = {
value: { value: {
string: "username123123", string: "username123123",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -84,7 +83,6 @@ export const LoginData: ExportData = {
value: { value: {
totp: "otpseed777", totp: "otpseed777",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const MedicalRecordData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1641220207, createdAt: 1641220207,
updatedAt: 1641220326, updatedAt: 1641220326,
trashed: false, state: "active",
categoryUuid: "113", categoryUuid: "113",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
date: 1641038460, date: 1641038460,
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "some hospital/clinic", string: "some hospital/clinic",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -74,7 +72,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "Some Doctor", string: "Some Doctor",
}, },
indexAtSource: 2,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -91,7 +88,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "Me", string: "Me",
}, },
indexAtSource: 3,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -108,7 +104,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "unwell", string: "unwell",
}, },
indexAtSource: 4,
guarded: true, guarded: true,
multiline: true, multiline: true,
dontGenerate: false, dontGenerate: false,
@@ -131,7 +126,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "Insuline", string: "Insuline",
}, },
indexAtSource: 0,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -148,7 +142,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "1", string: "1",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -165,7 +158,6 @@ export const MedicalRecordData: ExportData = {
value: { value: {
string: "multiple times a day", string: "multiple times a day",
}, },
indexAtSource: 2,
guarded: true, guarded: true,
multiline: true, multiline: true,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const MembershipData: ExportData = {
favIndex: 1, favIndex: 1,
createdAt: 1619467269, createdAt: 1619467269,
updatedAt: 1619467368, updatedAt: 1619467368,
trashed: false, state: "active",
categoryUuid: "105", categoryUuid: "105",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const MembershipData: ExportData = {
value: { value: {
string: "National Public Library", string: "National Public Library",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const MembershipData: ExportData = {
value: { value: {
url: "https://npl.nullvalue.gov.test", url: "https://npl.nullvalue.gov.test",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const MembershipData: ExportData = {
value: { value: {
phone: "9995555555", phone: "9995555555",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const MembershipData: ExportData = {
value: { value: {
string: "George Engels", string: "George Engels",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const MembershipData: ExportData = {
value: { value: {
monthYear: 199901, monthYear: 199901,
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const MembershipData: ExportData = {
value: { value: {
monthYear: 203412, monthYear: 203412,
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const MembershipData: ExportData = {
value: { value: {
string: "64783862", string: "64783862",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const MembershipData: ExportData = {
value: { value: {
concealed: "19191", concealed: "19191",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const OnePuxExampleFile: ExportData = {
favIndex: 1, favIndex: 1,
createdAt: 1614298956, createdAt: 1614298956,
updatedAt: 1635346445, updatedAt: 1635346445,
trashed: false, state: "active",
categoryUuid: "001", categoryUuid: "001",
details: { details: {
loginFields: [ loginFields: [
@@ -50,7 +50,6 @@ export const OnePuxExampleFile: ExportData = {
value: { value: {
concealed: "12345", concealed: "12345",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const OutdoorLicenseData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619467374, createdAt: 1619467374,
updatedAt: 1619467492, updatedAt: 1619467492,
trashed: false, state: "active",
categoryUuid: "104", categoryUuid: "104",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
string: "Cash Bandit", string: "Cash Bandit",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
date: 1617278460, date: 1617278460,
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
date: 2343124860, date: 2343124860,
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
string: "Bananas,blueberries,corn", string: "Bananas,blueberries,corn",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
string: "100/each", string: "100/each",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
string: "Washington", string: "Washington",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const OutdoorLicenseData: ExportData = {
value: { value: {
string: "United States of America", string: "United States of America",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const PassportData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619467498, createdAt: 1619467498,
updatedAt: 1619467655, updatedAt: 1619467655,
trashed: false, state: "active",
categoryUuid: "106", categoryUuid: "106",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "US Passport", string: "US Passport",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "United States of America", string: "United States of America",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "76436847", string: "76436847",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "David Global", string: "David Global",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const PassportData: ExportData = {
value: { value: {
gender: "female", gender: "female",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "International", string: "International",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "Department of State", string: "Department of State",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const PassportData: ExportData = {
value: { value: {
date: 418046460, date: 418046460,
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -169,7 +161,6 @@ export const PassportData: ExportData = {
value: { value: {
string: "A cave somewhere in Maine", string: "A cave somewhere in Maine",
}, },
indexAtSource: 8,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -185,7 +176,6 @@ export const PassportData: ExportData = {
value: { value: {
date: 1577880060, date: 1577880060,
}, },
indexAtSource: 9,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -201,7 +191,6 @@ export const PassportData: ExportData = {
value: { value: {
date: 2524651260, date: 2524651260,
}, },
indexAtSource: 10,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const PasswordData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465796, createdAt: 1619465796,
updatedAt: 1619465869, updatedAt: 1619465869,
trashed: false, state: "active",
categoryUuid: "005", categoryUuid: "005",
details: { details: {
loginFields: [], loginFields: [],

View File

@@ -26,7 +26,7 @@ export const RewardsProgramData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619467659, createdAt: 1619467659,
updatedAt: 1619467765, updatedAt: 1619467765,
trashed: false, state: "active",
categoryUuid: "107", categoryUuid: "107",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
string: "Super Cool Store Co.", string: "Super Cool Store Co.",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
string: "Chef Coldroom", string: "Chef Coldroom",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
string: "member-29813569", string: "member-29813569",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
clipboardFilter: clipboardFilter:
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
@@ -91,7 +88,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
concealed: "99913", concealed: "99913",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -113,7 +109,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
string: "additional member id", string: "additional member id",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -129,7 +124,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
monthYear: 202101, monthYear: 202101,
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -145,7 +139,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
phone: "123456", phone: "123456",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -161,7 +154,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
phone: "123456", phone: "123456",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -177,7 +169,6 @@ export const RewardsProgramData: ExportData = {
value: { value: {
url: "supercoolstore.com", url: "supercoolstore.com",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const SecureNoteData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619465226, createdAt: 1619465226,
updatedAt: 1619465278, updatedAt: 1619465278,
trashed: false, state: "active",
categoryUuid: "003", categoryUuid: "003",
details: { details: {
loginFields: [], loginFields: [],

View File

@@ -26,7 +26,7 @@ export const ServerData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1619467769, createdAt: 1619467769,
updatedAt: 1619467906, updatedAt: 1619467906,
trashed: false, state: "active",
categoryUuid: "110", categoryUuid: "110",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "https://coolserver.nullvalue.test", string: "https://coolserver.nullvalue.test",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "frankly-notsure", string: "frankly-notsure",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const ServerData: ExportData = {
value: { value: {
concealed: "*&YHJI87yjy78u", concealed: "*&YHJI87yjy78u",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -95,7 +92,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "https://coolserver.nullvalue.test/admin", string: "https://coolserver.nullvalue.test/admin",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -111,7 +107,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "frankly-idontknowwhatimdoing", string: "frankly-idontknowwhatimdoing",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -127,7 +122,6 @@ export const ServerData: ExportData = {
value: { value: {
concealed: "^%RY&^YUiju8iUYHJI(U", concealed: "^%RY&^YUiju8iUYHJI(U",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -149,7 +143,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "Private Hosting Provider Inc.", string: "Private Hosting Provider Inc.",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -165,7 +158,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "https://phpi.nullvalue.test", string: "https://phpi.nullvalue.test",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -181,7 +173,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "https://phpi.nullvalue.test/support", string: "https://phpi.nullvalue.test/support",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -197,7 +188,6 @@ export const ServerData: ExportData = {
value: { value: {
string: "8882569382", string: "8882569382",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const SoftwareLicenseData: ExportData = {
favIndex: 1, favIndex: 1,
createdAt: 1619467985, createdAt: 1619467985,
updatedAt: 1619468230, updatedAt: 1619468230,
trashed: false, state: "active",
categoryUuid: "100", categoryUuid: "100",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "5.10.1000", string: "5.10.1000",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "265453-13457355-847327", string: "265453-13457355-847327",
}, },
indexAtSource: 1,
guarded: true, guarded: true,
multiline: true, multiline: true,
dontGenerate: false, dontGenerate: false,
@@ -79,7 +77,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "Kay Riddler", string: "Kay Riddler",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -98,7 +95,6 @@ export const SoftwareLicenseData: ExportData = {
provider: null, provider: null,
}, },
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -114,7 +110,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "Riddles and Jigsaw Puzzles GmbH", string: "Riddles and Jigsaw Puzzles GmbH",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -136,7 +131,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
url: "https://limuxcompany.nullvalue.test/5.10.1000/isos", url: "https://limuxcompany.nullvalue.test/5.10.1000/isos",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -152,7 +146,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "Limux Software and Hardware", string: "Limux Software and Hardware",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -168,7 +161,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
url: "https://limuxcompany.nullvalue.test/", url: "https://limuxcompany.nullvalue.test/",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -184,7 +176,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "$999", string: "$999",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -203,7 +194,6 @@ export const SoftwareLicenseData: ExportData = {
provider: null, provider: null,
}, },
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -225,7 +215,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
date: 1617278460, date: 1617278460,
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -241,7 +230,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "594839", string: "594839",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -257,7 +245,6 @@ export const SoftwareLicenseData: ExportData = {
value: { value: {
string: "$1086.59", string: "$1086.59",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -26,7 +26,7 @@ export const SSNData: ExportData = {
favIndex: 1, favIndex: 1,
createdAt: 1619467910, createdAt: 1619467910,
updatedAt: 1619467982, updatedAt: 1619467982,
trashed: false, state: "active",
categoryUuid: "108", categoryUuid: "108",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const SSNData: ExportData = {
value: { value: {
string: "Jack Judd", string: "Jack Judd",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const SSNData: ExportData = {
value: { value: {
concealed: "131-216-1900", concealed: "131-216-1900",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: true, dontGenerate: true,

View File

@@ -26,7 +26,7 @@ export const WirelessRouterData: ExportData = {
favIndex: 0, favIndex: 0,
createdAt: 1577652307, createdAt: 1577652307,
updatedAt: 1577652307, updatedAt: 1577652307,
trashed: false, state: "active",
categoryUuid: "109", categoryUuid: "109",
details: { details: {
loginFields: [], loginFields: [],
@@ -41,7 +41,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
string: "pixel 2Xl", string: "pixel 2Xl",
}, },
indexAtSource: 0,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -57,7 +56,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
concealed: "BqatGTVQ9TCN72tLbjrsHqkb", concealed: "BqatGTVQ9TCN72tLbjrsHqkb",
}, },
indexAtSource: 1,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -73,7 +71,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
string: "127.0.0.1", string: "127.0.0.1",
}, },
indexAtSource: 2,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -89,7 +86,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
string: "some airportId", string: "some airportId",
}, },
indexAtSource: 3,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -105,7 +101,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
string: "some network name", string: "some network name",
}, },
indexAtSource: 4,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -121,7 +116,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
menu: "WPA", menu: "WPA",
}, },
indexAtSource: 5,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -137,7 +131,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
concealed: "wifipassword", concealed: "wifipassword",
}, },
indexAtSource: 6,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,
@@ -153,7 +146,6 @@ export const WirelessRouterData: ExportData = {
value: { value: {
concealed: "diskpassword", concealed: "diskpassword",
}, },
indexAtSource: 7,
guarded: false, guarded: false,
multiline: false, multiline: false,
dontGenerate: false, dontGenerate: false,

View File

@@ -60,9 +60,17 @@ export class Parser {
// 3: url // 3: url
step = 3; step = 3;
let url = Utils.fromBufferToUtf8( const urlEncoded = this.readItem(reader);
this.decodeHexLoose(Utils.fromBufferToUtf8(this.readItem(reader))), let url =
); urlEncoded.length > 0 && urlEncoded[0] === 33 // 33 = '!'
? // URL is encrypted
await this.cryptoUtils.decryptAes256PlainWithDefault(
urlEncoded,
encryptionKey,
placeholder,
)
: // URL is not encrypted
Utils.fromBufferToUtf8(this.decodeHexLoose(Utils.fromBufferToUtf8(urlEncoded)));
// Ignore "group" accounts. They have no credentials. // Ignore "group" accounts. They have no credentials.
if (url == "http://group") { if (url == "http://group") {

View File

@@ -37,7 +37,7 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer {
// const personalVaults = account.vaults[0].filter((v) => v.attrs.type === VaultAttributeTypeEnum.Personal); // const personalVaults = account.vaults[0].filter((v) => v.attrs.type === VaultAttributeTypeEnum.Personal);
account.vaults.forEach((vault: VaultsEntity) => { account.vaults.forEach((vault: VaultsEntity) => {
vault.items.forEach((item: Item) => { vault.items.forEach((item: Item) => {
if (item.trashed === true) { if (item.state === "archived") {
return; return;
} }

View File

@@ -53,7 +53,7 @@ export interface Item {
favIndex: number; favIndex: number;
createdAt: number; createdAt: number;
updatedAt: number; updatedAt: number;
trashed?: boolean; state: "active" | "archived";
categoryUuid: string; categoryUuid: string;
details: Details; details: Details;
overview: Overview; overview: Overview;
@@ -88,12 +88,12 @@ export interface SectionsEntity {
title: string; title: string;
name?: string | null; name?: string | null;
fields?: FieldsEntity[] | null; fields?: FieldsEntity[] | null;
hideAddAnotherField?: boolean | null;
} }
export interface FieldsEntity { export interface FieldsEntity {
title: string; title: string;
id: string; id: string;
value: Value; value: Value;
indexAtSource: number;
guarded: boolean; guarded: boolean;
multiline: boolean; multiline: boolean;
dontGenerate: boolean; dontGenerate: boolean;
@@ -153,6 +153,8 @@ export interface Overview {
pbe?: number | null; pbe?: number | null;
pgrng?: boolean | null; pgrng?: boolean | null;
tags?: string[] | null; tags?: string[] | null;
icons?: string | null;
watchtowerExclusions?: string | null;
} }
export interface UrlsEntity { export interface UrlsEntity {
label: string; label: string;

View File

@@ -79,6 +79,9 @@ type BaseCipherFormConfig = {
* List of organizations that the user can create ciphers for. * List of organizations that the user can create ciphers for.
*/ */
organizations?: Organization[]; organizations?: Organization[];
/** Hides the fields that are only applicable to individuals, useful in the Admin Console where folders aren't applicable */
hideIndividualVaultFields?: true;
}; };
/** /**

View File

@@ -2,6 +2,7 @@
<bit-section-header> <bit-section-header>
<h2 bitTypography="h6">{{ "itemDetails" | i18n }}</h2> <h2 bitTypography="h6">{{ "itemDetails" | i18n }}</h2>
<button <button
*ngIf="!config.hideIndividualVaultFields"
slot="end" slot="end"
type="button" type="button"
size="small" size="small"
@@ -18,7 +19,11 @@
<input bitInput formControlName="name" /> <input bitInput formControlName="name" />
</bit-form-field> </bit-form-field>
<div class="tw-grid tw-grid-cols-2 tw-gap-1"> <div class="tw-grid tw-grid-cols-2 tw-gap-1">
<bit-form-field *ngIf="showOwnership" [disableMargin]="!showCollectionsControl"> <bit-form-field
*ngIf="showOwnership"
[disableMargin]="!showCollectionsControl"
[class.tw-col-span-2]="config.hideIndividualVaultFields"
>
<bit-label>{{ "owner" | i18n }}</bit-label> <bit-label>{{ "owner" | i18n }}</bit-label>
<bit-select formControlName="organizationId"> <bit-select formControlName="organizationId">
<bit-option <bit-option
@@ -36,6 +41,7 @@
<bit-form-field <bit-form-field
[class.tw-col-span-2]="!showOwnership" [class.tw-col-span-2]="!showOwnership"
[disableMargin]="!showCollectionsControl" [disableMargin]="!showCollectionsControl"
*ngIf="!config.hideIndividualVaultFields"
> >
<bit-label>{{ "folder" | i18n }}</bit-label> <bit-label>{{ "folder" | i18n }}</bit-label>
<bit-select formControlName="folderId"> <bit-select formControlName="folderId">

View File

@@ -1,5 +1,5 @@
import { inject, Injectable } from "@angular/core"; import { inject, Injectable } from "@angular/core";
import { combineLatest, firstValueFrom, map } from "rxjs"; import { combineLatest, filter, firstValueFrom, map, switchMap } from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@@ -39,9 +39,21 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService {
await firstValueFrom( await firstValueFrom(
combineLatest([ combineLatest([
this.organizations$, this.organizations$,
this.collectionService.decryptedCollections$, this.collectionService.encryptedCollections$.pipe(
switchMap((c) =>
this.collectionService.decryptedCollections$.pipe(
filter((d) => d.length === c.length), // Ensure all collections have been decrypted
),
),
),
this.allowPersonalOwnership$, this.allowPersonalOwnership$,
this.folderService.folderViews$, this.folderService.folders$.pipe(
switchMap((f) =>
this.folderService.folderViews$.pipe(
filter((d) => d.length - 1 === f.length), // -1 for "No Folder" in folderViews$
),
),
),
this.getCipher(cipherId), this.getCipher(cipherId),
]), ]),
); );

14
package-lock.json generated
View File

@@ -24,6 +24,7 @@
"@angular/platform-browser": "16.2.12", "@angular/platform-browser": "16.2.12",
"@angular/platform-browser-dynamic": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12",
"@angular/router": "16.2.12", "@angular/router": "16.2.12",
"@bitwarden/sdk-internal": "0.1.3",
"@electron/fuses": "1.8.0", "@electron/fuses": "1.8.0",
"@koa/multer": "3.0.2", "@koa/multer": "3.0.2",
"@koa/router": "12.0.1", "@koa/router": "12.0.1",
@@ -193,11 +194,11 @@
}, },
"apps/browser": { "apps/browser": {
"name": "@bitwarden/browser", "name": "@bitwarden/browser",
"version": "2024.10.0" "version": "2024.10.1"
}, },
"apps/cli": { "apps/cli": {
"name": "@bitwarden/cli", "name": "@bitwarden/cli",
"version": "2024.9.1", "version": "2024.10.0",
"license": "SEE LICENSE IN LICENSE.txt", "license": "SEE LICENSE IN LICENSE.txt",
"dependencies": { "dependencies": {
"@koa/multer": "3.0.2", "@koa/multer": "3.0.2",
@@ -233,7 +234,7 @@
}, },
"apps/desktop": { "apps/desktop": {
"name": "@bitwarden/desktop", "name": "@bitwarden/desktop",
"version": "2024.9.2", "version": "2024.10.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "GPL-3.0" "license": "GPL-3.0"
}, },
@@ -247,7 +248,7 @@
}, },
"apps/web": { "apps/web": {
"name": "@bitwarden/web-vault", "name": "@bitwarden/web-vault",
"version": "2024.10.0" "version": "2024.10.1"
}, },
"libs/admin-console": { "libs/admin-console": {
"name": "@bitwarden/admin-console", "name": "@bitwarden/admin-console",
@@ -4625,6 +4626,11 @@
"resolved": "libs/platform", "resolved": "libs/platform",
"link": true "link": true
}, },
"node_modules/@bitwarden/sdk-internal": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.1.3.tgz",
"integrity": "sha512-zk9DyYMjylVLdljeLn3OLBcD939Hg/qMNJ2FxbyjiSKtcOcgglXgYmbcS01NRFFfM9REbn+j+2fWbQo6N+8SHw=="
},
"node_modules/@bitwarden/vault": { "node_modules/@bitwarden/vault": {
"resolved": "libs/vault", "resolved": "libs/vault",
"link": true "link": true

View File

@@ -157,6 +157,7 @@
"@angular/platform-browser": "16.2.12", "@angular/platform-browser": "16.2.12",
"@angular/platform-browser-dynamic": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12",
"@angular/router": "16.2.12", "@angular/router": "16.2.12",
"@bitwarden/sdk-internal": "0.1.3",
"@electron/fuses": "1.8.0", "@electron/fuses": "1.8.0",
"@koa/multer": "3.0.2", "@koa/multer": "3.0.2",
"@koa/router": "12.0.1", "@koa/router": "12.0.1",