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: {
prefix: "<rootDir>/", "@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
}), "<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
...pathsToModuleNameMapper(compilerOptions?.paths || {}, {
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: {
// lets us use @bitwarden/common/spec in web tests // Replace ESM SDK with Node compatible SDK
{ "@bitwarden/common/spec": ["../../libs/common/spec"], ...(compilerOptions?.paths ?? {}) }, "@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
{ "<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
prefix: "<rootDir>/", ...pathsToModuleNameMapper(
}, {
), // lets us use @bitwarden/common/spec in web tests
"@bitwarden/common/spec": ["../../libs/common/spec"],
...(compilerOptions?.paths ?? {}),
},
{
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: {
prefix: "<rootDir>/", "@bitwarden/common/platform/services/sdk/default-sdk-client-factory":
}), "<rootDir>/../../libs/common/spec/jest-sdk-client-factory",
...pathsToModuleNameMapper(compilerOptions?.paths || {}, {
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

@@ -22,7 +22,7 @@ export class Parser {
/* /*
May return null when the chunk does not represent an account. May return null when the chunk does not represent an account.
All secure notes are ACCTs but not all of them store account information. All secure notes are ACCTs but not all of them store account information.
TODO: Add a test for the folder case! TODO: Add a test for the folder case!
TODO: Add a test case that covers secure note account! TODO: Add a test case that covers secure note account!
*/ */
@@ -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",