mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 17:23:37 +00:00
Merge branch 'master' into feature/org-admin-refresh
This commit is contained in:
11
.github/workflows/build-web.yml
vendored
11
.github/workflows/build-web.yml
vendored
@@ -267,16 +267,23 @@ jobs:
|
|||||||
- name: Login to Azure ACR
|
- name: Login to Azure ACR
|
||||||
run: az acr login -n bitwardenqa
|
run: az acr login -n bitwardenqa
|
||||||
|
|
||||||
- name: Tag and Push RC to Azure ACR QA registry
|
- name: Tag and Push to Azure QA ACR
|
||||||
env:
|
env:
|
||||||
REGISTRY: bitwardenqa.azurecr.io
|
REGISTRY: bitwardenqa.azurecr.io
|
||||||
run: |
|
run: |
|
||||||
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name
|
if [[ $(grep "pull" <<< "${GITHUB_REF}") ]]; then
|
||||||
|
IMAGE_TAG=$(echo "${GITHUB_HEAD_REF}" | sed "s#/#-#g")
|
||||||
|
else
|
||||||
|
IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g")
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$IMAGE_TAG" == "master" ]]; then
|
if [[ "$IMAGE_TAG" == "master" ]]; then
|
||||||
IMAGE_TAG=dev
|
IMAGE_TAG=dev
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker tag bitwarden/web \
|
docker tag bitwarden/web \
|
||||||
$REGISTRY/web-sh:$IMAGE_TAG
|
$REGISTRY/web-sh:$IMAGE_TAG
|
||||||
|
|
||||||
docker push $REGISTRY/web-sh:$IMAGE_TAG
|
docker push $REGISTRY/web-sh:$IMAGE_TAG
|
||||||
|
|
||||||
- name: Log out of Docker
|
- name: Log out of Docker
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"devFlags": {
|
"devFlags": {
|
||||||
"storeSessionDecrypted": false
|
"storeSessionDecrypted": false,
|
||||||
|
"managedEnvironment": {
|
||||||
|
"base": "https://localhost:8080"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"flags": {}
|
"flags": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import MainBackground from "./background/main.background";
|
import MainBackground from "./background/main.background";
|
||||||
import { onCommandListener } from "./listeners/onCommandListener";
|
import { onCommandListener } from "./listeners/onCommandListener";
|
||||||
|
import { onInstallListener } from "./listeners/onInstallListener";
|
||||||
|
|
||||||
const manifest = chrome.runtime.getManifest();
|
const manifest = chrome.runtime.getManifest();
|
||||||
|
|
||||||
if (manifest.manifest_version === 3) {
|
if (manifest.manifest_version === 3) {
|
||||||
chrome.commands.onCommand.addListener(onCommandListener);
|
chrome.commands.onCommand.addListener(onCommandListener);
|
||||||
|
chrome.runtime.onInstalled.addListener(onInstallListener);
|
||||||
} else {
|
} else {
|
||||||
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
||||||
bitwardenMain.bootstrap().then(() => {
|
bitwardenMain.bootstrap().then(() => {
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import { AuditService } from "@bitwarden/common/services/audit.service";
|
|||||||
import { AuthService } from "@bitwarden/common/services/auth.service";
|
import { AuthService } from "@bitwarden/common/services/auth.service";
|
||||||
import { CipherService } from "@bitwarden/common/services/cipher.service";
|
import { CipherService } from "@bitwarden/common/services/cipher.service";
|
||||||
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
import { CollectionService } from "@bitwarden/common/services/collection.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
|
||||||
import { ContainerService } from "@bitwarden/common/services/container.service";
|
import { ContainerService } from "@bitwarden/common/services/container.service";
|
||||||
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
||||||
import { EventService } from "@bitwarden/common/services/event.service";
|
import { EventService } from "@bitwarden/common/services/event.service";
|
||||||
@@ -55,7 +54,6 @@ import { ExportService } from "@bitwarden/common/services/export.service";
|
|||||||
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
|
||||||
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
|
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
|
import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service";
|
||||||
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
|
|
||||||
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
|
import { NotificationsService } from "@bitwarden/common/services/notifications.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/services/organization.service";
|
import { OrganizationService } from "@bitwarden/common/services/organization.service";
|
||||||
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
|
import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service";
|
||||||
@@ -74,7 +72,6 @@ import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
|||||||
import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service";
|
import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
|
||||||
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
||||||
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
|
||||||
|
|
||||||
import { BrowserApi } from "../browser/browserApi";
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
import { SafariApp } from "../browser/safariApp";
|
import { SafariApp } from "../browser/safariApp";
|
||||||
@@ -85,15 +82,11 @@ import { StateService as StateServiceAbstraction } from "../services/abstraction
|
|||||||
import AutofillService from "../services/autofill.service";
|
import AutofillService from "../services/autofill.service";
|
||||||
import { BrowserEnvironmentService } from "../services/browser-environment.service";
|
import { BrowserEnvironmentService } from "../services/browser-environment.service";
|
||||||
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
||||||
import BrowserLocalStorageService from "../services/browserLocalStorage.service";
|
|
||||||
import BrowserMessagingService from "../services/browserMessaging.service";
|
import BrowserMessagingService from "../services/browserMessaging.service";
|
||||||
import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service";
|
import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service";
|
||||||
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
||||||
import { FolderService } from "../services/folders/folder.service";
|
import { FolderService } from "../services/folders/folder.service";
|
||||||
import I18nService from "../services/i18n.service";
|
import I18nService from "../services/i18n.service";
|
||||||
import { KeyGenerationService } from "../services/keyGeneration.service";
|
|
||||||
import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service";
|
|
||||||
import { StateService } from "../services/state.service";
|
|
||||||
import { VaultFilterService } from "../services/vaultFilter.service";
|
import { VaultFilterService } from "../services/vaultFilter.service";
|
||||||
import VaultTimeoutService from "../services/vaultTimeout.service";
|
import VaultTimeoutService from "../services/vaultTimeout.service";
|
||||||
|
|
||||||
@@ -104,6 +97,17 @@ import IconDetails from "./models/iconDetails";
|
|||||||
import { NativeMessagingBackground } from "./nativeMessaging.background";
|
import { NativeMessagingBackground } from "./nativeMessaging.background";
|
||||||
import NotificationBackground from "./notification.background";
|
import NotificationBackground from "./notification.background";
|
||||||
import RuntimeBackground from "./runtime.background";
|
import RuntimeBackground from "./runtime.background";
|
||||||
|
import { cryptoFunctionServiceFactory } from "./service_factories/crypto-function-service.factory";
|
||||||
|
import { encryptServiceFactory } from "./service_factories/encrypt-service.factory";
|
||||||
|
import { environmentServiceFactory } from "./service_factories/environment-service.factory";
|
||||||
|
import { logServiceFactory } from "./service_factories/log-service.factory";
|
||||||
|
import { stateMigrationServiceFactory } from "./service_factories/state-migration-service.factory";
|
||||||
|
import { stateServiceFactory } from "./service_factories/state-service.factory";
|
||||||
|
import {
|
||||||
|
diskStorageServiceFactory,
|
||||||
|
memoryStorageServiceFactory,
|
||||||
|
secureStorageServiceFactory,
|
||||||
|
} from "./service_factories/storage-service.factory";
|
||||||
import TabsBackground from "./tabs.background";
|
import TabsBackground from "./tabs.background";
|
||||||
import WebRequestBackground from "./webRequest.background";
|
import WebRequestBackground from "./webRequest.background";
|
||||||
|
|
||||||
@@ -195,33 +199,40 @@ export default class MainBackground {
|
|||||||
const logoutCallback = async (expired: boolean, userId?: string) =>
|
const logoutCallback = async (expired: boolean, userId?: string) =>
|
||||||
await this.logout(expired, userId);
|
await this.logout(expired, userId);
|
||||||
|
|
||||||
|
const services: Record<string, unknown> = {};
|
||||||
|
const factoryOptions = {
|
||||||
|
logServiceOptions: {
|
||||||
|
isDev: false,
|
||||||
|
},
|
||||||
|
cryptoFunctionServiceOptions: {
|
||||||
|
win: window,
|
||||||
|
},
|
||||||
|
stateMigrationServiceOptions: {
|
||||||
|
stateFactory: new StateFactory(GlobalState, Account),
|
||||||
|
},
|
||||||
|
stateServiceOptions: {
|
||||||
|
stateFactory: new StateFactory(GlobalState, Account),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
this.messagingService = isPrivateMode
|
this.messagingService = isPrivateMode
|
||||||
? new BrowserMessagingPrivateModeBackgroundService()
|
? new BrowserMessagingPrivateModeBackgroundService()
|
||||||
: new BrowserMessagingService();
|
: new BrowserMessagingService();
|
||||||
this.logService = new ConsoleLogService(false);
|
this.logService = logServiceFactory(services, factoryOptions);
|
||||||
this.cryptoFunctionService = new WebCryptoFunctionService(window);
|
this.cryptoFunctionService = cryptoFunctionServiceFactory(services, factoryOptions);
|
||||||
this.storageService = new BrowserLocalStorageService();
|
this.storageService = diskStorageServiceFactory(services, factoryOptions);
|
||||||
this.secureStorageService = new BrowserLocalStorageService();
|
this.secureStorageService = secureStorageServiceFactory(services, factoryOptions);
|
||||||
this.memoryStorageService =
|
this.memoryStorageService = memoryStorageServiceFactory(services, {
|
||||||
chrome.runtime.getManifest().manifest_version == 3
|
...factoryOptions,
|
||||||
? new LocalBackedSessionStorageService(
|
encryptServiceOptions: {
|
||||||
new EncryptService(this.cryptoFunctionService, this.logService, false),
|
logMacFailures: false,
|
||||||
new KeyGenerationService(this.cryptoFunctionService)
|
},
|
||||||
)
|
});
|
||||||
: new MemoryStorageService();
|
this.stateMigrationService = stateMigrationServiceFactory(services, factoryOptions);
|
||||||
this.stateMigrationService = new StateMigrationService(
|
this.stateService = stateServiceFactory(services, {
|
||||||
this.storageService,
|
...factoryOptions,
|
||||||
this.secureStorageService,
|
encryptServiceOptions: { logMacFailures: false },
|
||||||
new StateFactory(GlobalState, Account)
|
});
|
||||||
);
|
|
||||||
this.stateService = new StateService(
|
|
||||||
this.storageService,
|
|
||||||
this.secureStorageService,
|
|
||||||
this.memoryStorageService,
|
|
||||||
this.logService,
|
|
||||||
this.stateMigrationService,
|
|
||||||
new StateFactory(GlobalState, Account)
|
|
||||||
);
|
|
||||||
this.platformUtilsService = new BrowserPlatformUtilsService(
|
this.platformUtilsService = new BrowserPlatformUtilsService(
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
@@ -245,7 +256,13 @@ export default class MainBackground {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
|
this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
|
||||||
this.encryptService = new EncryptService(this.cryptoFunctionService, this.logService, true);
|
this.encryptService = encryptServiceFactory(services, {
|
||||||
|
...factoryOptions,
|
||||||
|
encryptServiceOptions: {
|
||||||
|
logMacFailures: true,
|
||||||
|
},
|
||||||
|
alwaysInitializeNewService: true,
|
||||||
|
}); // Update encrypt service with new instances
|
||||||
this.cryptoService = new BrowserCryptoService(
|
this.cryptoService = new BrowserCryptoService(
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
@@ -255,7 +272,12 @@ export default class MainBackground {
|
|||||||
);
|
);
|
||||||
this.tokenService = new TokenService(this.stateService);
|
this.tokenService = new TokenService(this.stateService);
|
||||||
this.appIdService = new AppIdService(this.storageService);
|
this.appIdService = new AppIdService(this.storageService);
|
||||||
this.environmentService = new BrowserEnvironmentService(this.stateService, this.logService);
|
this.environmentService = environmentServiceFactory(services, {
|
||||||
|
...factoryOptions,
|
||||||
|
encryptServiceOptions: {
|
||||||
|
logMacFailures: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
this.apiService = new ApiService(
|
this.apiService = new ApiService(
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||||
|
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
||||||
|
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
|
||||||
|
type CryptoFunctionServiceFactoryOptions = FactoryOptions & {
|
||||||
|
cryptoFunctionServiceOptions: {
|
||||||
|
win: Window | typeof global;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CryptoFunctionServiceInitOptions = CryptoFunctionServiceFactoryOptions;
|
||||||
|
|
||||||
|
export function cryptoFunctionServiceFactory(
|
||||||
|
cache: { cryptoFunctionService?: CryptoFunctionService } & CachedServices,
|
||||||
|
opts: CryptoFunctionServiceFactoryOptions
|
||||||
|
): CryptoFunctionService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"cryptoFunctionService",
|
||||||
|
opts,
|
||||||
|
() => new WebCryptoFunctionService(opts.cryptoFunctionServiceOptions.win)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
||||||
|
|
||||||
|
import {
|
||||||
|
cryptoFunctionServiceFactory,
|
||||||
|
CryptoFunctionServiceInitOptions,
|
||||||
|
} from "./crypto-function-service.factory";
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
import { LogServiceInitOptions, logServiceFactory } from "./log-service.factory";
|
||||||
|
|
||||||
|
type EncryptServiceFactoryOptions = FactoryOptions & {
|
||||||
|
encryptServiceOptions: {
|
||||||
|
logMacFailures: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EncryptServiceInitOptions = EncryptServiceFactoryOptions &
|
||||||
|
CryptoFunctionServiceInitOptions &
|
||||||
|
LogServiceInitOptions;
|
||||||
|
|
||||||
|
export function encryptServiceFactory(
|
||||||
|
cache: { encryptService?: EncryptService } & CachedServices,
|
||||||
|
opts: EncryptServiceInitOptions
|
||||||
|
): EncryptService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"encryptService",
|
||||||
|
opts,
|
||||||
|
() =>
|
||||||
|
new EncryptService(
|
||||||
|
cryptoFunctionServiceFactory(cache, opts),
|
||||||
|
logServiceFactory(cache, opts),
|
||||||
|
opts.encryptServiceOptions.logMacFailures
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { BrowserEnvironmentService } from "../../services/browser-environment.service";
|
||||||
|
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
|
import {
|
||||||
|
stateServiceFactory as stateServiceFactory,
|
||||||
|
StateServiceInitOptions,
|
||||||
|
} from "./state-service.factory";
|
||||||
|
|
||||||
|
type EnvironmentServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type EnvironmentServiceInitOptions = EnvironmentServiceFactoryOptions &
|
||||||
|
StateServiceInitOptions &
|
||||||
|
LogServiceInitOptions;
|
||||||
|
|
||||||
|
export function environmentServiceFactory(
|
||||||
|
cache: { environmentService?: BrowserEnvironmentService } & CachedServices,
|
||||||
|
opts: EnvironmentServiceInitOptions
|
||||||
|
): BrowserEnvironmentService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"environmentService",
|
||||||
|
opts,
|
||||||
|
() =>
|
||||||
|
new BrowserEnvironmentService(
|
||||||
|
stateServiceFactory(cache, opts),
|
||||||
|
logServiceFactory(cache, opts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export type CachedServices = Record<string, any>;
|
||||||
|
|
||||||
|
export type FactoryOptions = {
|
||||||
|
alwaysInitializeNewService?: boolean;
|
||||||
|
doNotStoreInitializedService?: boolean;
|
||||||
|
[optionsKey: string]: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function factory<
|
||||||
|
TCache extends CachedServices,
|
||||||
|
TName extends keyof TCache,
|
||||||
|
TOpts extends FactoryOptions
|
||||||
|
>(cachedServices: TCache, name: TName, opts: TOpts, factory: () => TCache[TName]): TCache[TName] {
|
||||||
|
let instance = cachedServices[name];
|
||||||
|
if (opts.alwaysInitializeNewService || !instance) {
|
||||||
|
instance = factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.doNotStoreInitializedService) {
|
||||||
|
cachedServices[name] = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance as TCache[TName];
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { KeyGenerationService } from "../../services/keyGeneration.service";
|
||||||
|
|
||||||
|
import {
|
||||||
|
cryptoFunctionServiceFactory,
|
||||||
|
CryptoFunctionServiceInitOptions,
|
||||||
|
} from "./crypto-function-service.factory";
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
|
||||||
|
type KeyGenerationServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type KeyGenerationServiceInitOptions = KeyGenerationServiceFactoryOptions &
|
||||||
|
CryptoFunctionServiceInitOptions;
|
||||||
|
|
||||||
|
export function keyGenerationServiceFactory(
|
||||||
|
cache: { keyGenerationService?: KeyGenerationService } & CachedServices,
|
||||||
|
opts: KeyGenerationServiceInitOptions
|
||||||
|
): KeyGenerationService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"keyGenerationService",
|
||||||
|
opts,
|
||||||
|
() => new KeyGenerationService(cryptoFunctionServiceFactory(cache, opts))
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
|
import { LogLevelType } from "@bitwarden/common/enums/logLevelType";
|
||||||
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
|
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
|
||||||
|
type LogServiceFactoryOptions = FactoryOptions & {
|
||||||
|
logServiceOptions: {
|
||||||
|
isDev: boolean;
|
||||||
|
filter?: (level: LogLevelType) => boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogServiceInitOptions = LogServiceFactoryOptions;
|
||||||
|
|
||||||
|
export function logServiceFactory(
|
||||||
|
cache: { logService?: LogService } & CachedServices,
|
||||||
|
opts: LogServiceInitOptions
|
||||||
|
): LogService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"logService",
|
||||||
|
opts,
|
||||||
|
() => new ConsoleLogService(opts.logServiceOptions.isDev, opts.logServiceOptions.filter)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
|
||||||
|
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
|
||||||
|
|
||||||
|
import { Account } from "../../models/account";
|
||||||
|
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
import {
|
||||||
|
diskStorageServiceFactory,
|
||||||
|
DiskStorageServiceInitOptions,
|
||||||
|
secureStorageServiceFactory,
|
||||||
|
SecureStorageServiceInitOptions,
|
||||||
|
} from "./storage-service.factory";
|
||||||
|
|
||||||
|
type StateMigrationServiceFactoryOptions = FactoryOptions & {
|
||||||
|
stateMigrationServiceOptions: {
|
||||||
|
stateFactory: StateFactory<GlobalState, Account>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StateMigrationServiceInitOptions = StateMigrationServiceFactoryOptions &
|
||||||
|
DiskStorageServiceInitOptions &
|
||||||
|
SecureStorageServiceInitOptions;
|
||||||
|
|
||||||
|
export function stateMigrationServiceFactory(
|
||||||
|
cache: { stateMigrationService?: StateMigrationService } & CachedServices,
|
||||||
|
opts: StateMigrationServiceInitOptions
|
||||||
|
): StateMigrationService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"stateMigrationService",
|
||||||
|
opts,
|
||||||
|
() =>
|
||||||
|
new StateMigrationService(
|
||||||
|
diskStorageServiceFactory(cache, opts),
|
||||||
|
secureStorageServiceFactory(cache, opts),
|
||||||
|
opts.stateMigrationServiceOptions.stateFactory
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
|
||||||
|
|
||||||
|
import { Account } from "../../models/account";
|
||||||
|
import { StateService } from "../../services/state.service";
|
||||||
|
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
|
||||||
|
import {
|
||||||
|
stateMigrationServiceFactory,
|
||||||
|
StateMigrationServiceInitOptions,
|
||||||
|
} from "./state-migration-service.factory";
|
||||||
|
import {
|
||||||
|
diskStorageServiceFactory,
|
||||||
|
secureStorageServiceFactory,
|
||||||
|
memoryStorageServiceFactory,
|
||||||
|
DiskStorageServiceInitOptions,
|
||||||
|
SecureStorageServiceInitOptions,
|
||||||
|
MemoryStorageServiceInitOptions,
|
||||||
|
} from "./storage-service.factory";
|
||||||
|
|
||||||
|
type StateServiceFactoryOptions = FactoryOptions & {
|
||||||
|
stateServiceOptions: {
|
||||||
|
useAccountCache?: boolean;
|
||||||
|
stateFactory: StateFactory<GlobalState, Account>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StateServiceInitOptions = StateServiceFactoryOptions &
|
||||||
|
DiskStorageServiceInitOptions &
|
||||||
|
SecureStorageServiceInitOptions &
|
||||||
|
MemoryStorageServiceInitOptions &
|
||||||
|
LogServiceInitOptions &
|
||||||
|
StateMigrationServiceInitOptions;
|
||||||
|
|
||||||
|
export function stateServiceFactory(
|
||||||
|
cache: { stateService?: StateService } & CachedServices,
|
||||||
|
opts: StateServiceInitOptions
|
||||||
|
): StateService {
|
||||||
|
return factory(
|
||||||
|
cache,
|
||||||
|
"stateService",
|
||||||
|
opts,
|
||||||
|
() =>
|
||||||
|
new StateService(
|
||||||
|
diskStorageServiceFactory(cache, opts),
|
||||||
|
secureStorageServiceFactory(cache, opts),
|
||||||
|
memoryStorageServiceFactory(cache, opts),
|
||||||
|
logServiceFactory(cache, opts),
|
||||||
|
stateMigrationServiceFactory(cache, opts),
|
||||||
|
opts.stateServiceOptions.stateFactory,
|
||||||
|
opts.stateServiceOptions.useAccountCache
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
||||||
|
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
|
||||||
|
|
||||||
|
import BrowserLocalStorageService from "../../services/browserLocalStorage.service";
|
||||||
|
import { LocalBackedSessionStorageService } from "../../services/localBackedSessionStorage.service";
|
||||||
|
|
||||||
|
import { encryptServiceFactory, EncryptServiceInitOptions } from "./encrypt-service.factory";
|
||||||
|
import { CachedServices, factory, FactoryOptions } from "./factory-options";
|
||||||
|
import {
|
||||||
|
keyGenerationServiceFactory,
|
||||||
|
KeyGenerationServiceInitOptions,
|
||||||
|
} from "./key-generation-service.factory";
|
||||||
|
|
||||||
|
type StorageServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
|
export type DiskStorageServiceInitOptions = StorageServiceFactoryOptions;
|
||||||
|
export type SecureStorageServiceInitOptions = StorageServiceFactoryOptions;
|
||||||
|
export type MemoryStorageServiceInitOptions = StorageServiceFactoryOptions &
|
||||||
|
EncryptServiceInitOptions &
|
||||||
|
KeyGenerationServiceInitOptions;
|
||||||
|
|
||||||
|
export function diskStorageServiceFactory(
|
||||||
|
cache: { diskStorageService?: AbstractStorageService } & CachedServices,
|
||||||
|
opts: DiskStorageServiceInitOptions
|
||||||
|
): AbstractStorageService {
|
||||||
|
return factory(cache, "diskStorageService", opts, () => new BrowserLocalStorageService());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function secureStorageServiceFactory(
|
||||||
|
cache: { secureStorageService?: AbstractStorageService } & CachedServices,
|
||||||
|
opts: SecureStorageServiceInitOptions
|
||||||
|
): AbstractStorageService {
|
||||||
|
return factory(cache, "secureStorageService", opts, () => new BrowserLocalStorageService());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function memoryStorageServiceFactory(
|
||||||
|
cache: { memoryStorageService?: AbstractStorageService } & CachedServices,
|
||||||
|
opts: MemoryStorageServiceInitOptions
|
||||||
|
): AbstractStorageService {
|
||||||
|
return factory(cache, "memoryStorageService", opts, () => {
|
||||||
|
if (chrome.runtime.getManifest().manifest_version == 3) {
|
||||||
|
return new LocalBackedSessionStorageService(
|
||||||
|
encryptServiceFactory(cache, opts),
|
||||||
|
keyGenerationServiceFactory(cache, opts)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new MemoryStorageService();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { GroupPolicyEnvironment } from "./types/group-policy-environment";
|
||||||
|
|
||||||
function getFlags<T>(envFlags: string | T): T {
|
function getFlags<T>(envFlags: string | T): T {
|
||||||
if (typeof envFlags === "string") {
|
if (typeof envFlags === "string") {
|
||||||
return JSON.parse(envFlags) as T;
|
return JSON.parse(envFlags) as T;
|
||||||
@@ -21,11 +23,13 @@ export function flagEnabled(flag: FlagName): boolean {
|
|||||||
*/
|
*/
|
||||||
export type DevFlags = {
|
export type DevFlags = {
|
||||||
storeSessionDecrypted?: boolean;
|
storeSessionDecrypted?: boolean;
|
||||||
|
managedEnvironment?: GroupPolicyEnvironment;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DevFlagName = keyof DevFlags;
|
export type DevFlagName = keyof DevFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Gets whether the given dev flag is truthy.
|
||||||
* Gets the value of a dev flag from environment.
|
* Gets the value of a dev flag from environment.
|
||||||
* Will always return false unless in development.
|
* Will always return false unless in development.
|
||||||
* @param flag The name of the dev flag to check
|
* @param flag The name of the dev flag to check
|
||||||
@@ -37,5 +41,21 @@ export function devFlagEnabled(flag: DevFlagName): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const devFlags = getFlags<DevFlags>(process.env.DEV_FLAGS);
|
const devFlags = getFlags<DevFlags>(process.env.DEV_FLAGS);
|
||||||
return devFlags[flag] == null || devFlags[flag];
|
return devFlags[flag] == null || !!devFlags[flag];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of a dev flag from environment.
|
||||||
|
* Will always return false unless in development.
|
||||||
|
* @param flag The name of the dev flag to check
|
||||||
|
* @returns The value of the flag
|
||||||
|
* @throws Error if the flag is not enabled
|
||||||
|
*/
|
||||||
|
export function devFlagValue<K extends DevFlagName>(flag: K): DevFlags[K] {
|
||||||
|
if (!devFlagEnabled(flag)) {
|
||||||
|
throw new Error(`This method should not be called, it is protected by a disabled dev flag.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const devFlags = getFlags<DevFlags>(process.env.DEV_FLAGS);
|
||||||
|
return devFlags[flag];
|
||||||
}
|
}
|
||||||
|
|||||||
38
apps/browser/src/listeners/onInstallListener.ts
Normal file
38
apps/browser/src/listeners/onInstallListener.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
|
||||||
|
|
||||||
|
import { environmentServiceFactory } from "../background/service_factories/environment-service.factory";
|
||||||
|
import { BrowserApi } from "../browser/browserApi";
|
||||||
|
import { Account } from "../models/account";
|
||||||
|
|
||||||
|
export function onInstallListener(details: chrome.runtime.InstalledDetails) {
|
||||||
|
const cache = {};
|
||||||
|
const opts = {
|
||||||
|
encryptServiceOptions: {
|
||||||
|
logMacFailures: false,
|
||||||
|
},
|
||||||
|
cryptoFunctionServiceOptions: {
|
||||||
|
win: self,
|
||||||
|
},
|
||||||
|
logServiceOptions: {
|
||||||
|
isDev: false,
|
||||||
|
},
|
||||||
|
stateServiceOptions: {
|
||||||
|
stateFactory: new StateFactory(GlobalState, Account),
|
||||||
|
},
|
||||||
|
stateMigrationServiceOptions: {
|
||||||
|
stateFactory: new StateFactory(GlobalState, Account),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const environmentService = environmentServiceFactory(cache, opts);
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (details.reason != null && details.reason === "install") {
|
||||||
|
BrowserApi.createNewTab("https://bitwarden.com/browser-start/");
|
||||||
|
|
||||||
|
if (await environmentService.hasManagedEnvironment()) {
|
||||||
|
await environmentService.setUrlsToManagedEnvironment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus-visible,
|
||||||
&.active {
|
&.active {
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
background-color: themed("boxBackgroundHoverColor");
|
background-color: themed("boxBackgroundHoverColor");
|
||||||
@@ -441,7 +441,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:not([type="file"]):focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,26 +26,19 @@
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
(click)="selectAllVaults()"
|
(click)="selectAllVaults()"
|
||||||
[ngClass]="{ active: !myVaultOnly && !selectOrganizationId }"
|
[ngClass]="{ active: !myVaultOnly && !selectOrganizationId }"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-filter" aria-hidden="true"></i>
|
||||||
{{ "allVaults" | i18n }}
|
{{ "allVaults" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button *ngIf="!enforcePersonalOwnwership" appStopClick (click)="selectMyVault()">
|
||||||
*ngIf="!enforcePersonalOwnwership"
|
|
||||||
appStopClick
|
|
||||||
appBlurClick
|
|
||||||
(click)="selectMyVault()"
|
|
||||||
>
|
|
||||||
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-user" aria-hidden="true"></i>
|
||||||
{{ "myVault" | i18n }}
|
{{ "myVault" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
*ngFor="let organization of organizations"
|
*ngFor="let organization of organizations"
|
||||||
appStopClick
|
appStopClick
|
||||||
appBlurClick
|
|
||||||
(click)="selectOrganization(organization)"
|
(click)="selectOrganization(organization)"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
|
|||||||
@@ -2,15 +2,8 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
|
|||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
|
||||||
|
|
||||||
type GroupPolicyEnvironment = {
|
import { devFlagEnabled, devFlagValue } from "../flags";
|
||||||
base?: string;
|
import { GroupPolicyEnvironment } from "../types/group-policy-environment";
|
||||||
webVault?: string;
|
|
||||||
api?: string;
|
|
||||||
identity?: string;
|
|
||||||
icons?: string;
|
|
||||||
notifications?: string;
|
|
||||||
events?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class BrowserEnvironmentService extends EnvironmentService {
|
export class BrowserEnvironmentService extends EnvironmentService {
|
||||||
constructor(stateService: StateService, private logService: LogService) {
|
constructor(stateService: StateService, private logService: LogService) {
|
||||||
@@ -41,7 +34,9 @@ export class BrowserEnvironmentService extends EnvironmentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getManagedEnvironment(): Promise<GroupPolicyEnvironment> {
|
getManagedEnvironment(): Promise<GroupPolicyEnvironment> {
|
||||||
return new Promise((resolve, reject) => {
|
return devFlagEnabled("managedEnvironment")
|
||||||
|
? new Promise((resolve) => resolve(devFlagValue("managedEnvironment")))
|
||||||
|
: new Promise((resolve, reject) => {
|
||||||
chrome.storage.managed.get("environment", (result) => {
|
chrome.storage.managed.get("environment", (result) => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
return reject(chrome.runtime.lastError);
|
return reject(chrome.runtime.lastError);
|
||||||
|
|||||||
9
apps/browser/src/types/group-policy-environment.ts
Normal file
9
apps/browser/src/types/group-policy-environment.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export type GroupPolicyEnvironment = {
|
||||||
|
base?: string;
|
||||||
|
webVault?: string;
|
||||||
|
api?: string;
|
||||||
|
identity?: string;
|
||||||
|
icons?: string;
|
||||||
|
notifications?: string;
|
||||||
|
events?: string;
|
||||||
|
};
|
||||||
@@ -281,7 +281,7 @@ export class Program extends BaseProgram {
|
|||||||
writeLn("", true);
|
writeLn("", true);
|
||||||
})
|
})
|
||||||
.action(async (cmd) => {
|
.action(async (cmd) => {
|
||||||
await this.exitIfLocked();
|
await this.exitIfNotAuthed();
|
||||||
const command = new SyncCommand(this.main.syncService);
|
const command = new SyncCommand(this.main.syncService);
|
||||||
const response = await command.run(cmd);
|
const response = await command.run(cmd);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
|
|||||||
@@ -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": "2022.8.1",
|
"version": "2022.8.2",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="modal fade" role="dialog" aria-modal="true" attr.aria-label="{{ 'settings' | i18n }}">
|
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="deleteAccountTitle">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<form
|
<form
|
||||||
class="modal-content"
|
class="modal-content"
|
||||||
@@ -13,7 +13,9 @@
|
|||||||
{{ "deleteAccountWarning" | i18n }}
|
{{ "deleteAccountWarning" | i18n }}
|
||||||
</app-callout>
|
</app-callout>
|
||||||
<div class="box last">
|
<div class="box last">
|
||||||
<div class="box-header">{{ "deleteAccount" | i18n }}</div>
|
<h1 class="box-header" id="deleteAccountTitle">
|
||||||
|
{{ "deleteAccount" | i18n }}
|
||||||
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-user-verification
|
<app-user-verification
|
||||||
ngDefaultControl
|
ngDefaultControl
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<div class="modal fade" role="dialog" aria-modal="true" attr.aria-label="{{ 'settings' | i18n }}">
|
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="selfHosteEnvironmentTitle">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<form class="modal-content" (ngSubmit)="submit()">
|
<form class="modal-content" (ngSubmit)="submit()">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h1 class="box-header" id="selfHosteEnvironmentTitle">
|
||||||
{{ "selfHostedEnvironment" | i18n }}
|
{{ "selfHostedEnvironment" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="baseUrl">{{ "baseUrl" | i18n }}</label>
|
<label for="baseUrl">{{ "baseUrl" | i18n }}</label>
|
||||||
@@ -24,13 +24,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
<button type="button" (click)="toggleCustom()" [attr.aria-expanded]="showCustom">
|
<button type="button" (click)="toggleCustom()" [attr.aria-expanded]="showCustom">
|
||||||
<i class="bwi bwi-plus-square" [hidden]="showCustom" aria-hidden="true"></i>
|
<i class="bwi bwi-plus-square" [hidden]="showCustom" aria-hidden="true"></i>
|
||||||
<i class="bwi bwi-minus-square" [hidden]="!showCustom" aria-hidden="true"></i>
|
<i class="bwi bwi-minus-square" [hidden]="!showCustom" aria-hidden="true"></i>
|
||||||
{{ "customEnvironment" | i18n }}
|
{{ "customEnvironment" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content" [hidden]="!showCustom">
|
<div class="box-content" [hidden]="!showCustom">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="webVaultUrl">{{ "webVaultUrl" | i18n }}</label>
|
<label for="webVaultUrl">{{ "webVaultUrl" | i18n }}</label>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="premiumTitle">
|
<h1 class="box-header" id="premiumTitle">
|
||||||
{{ "premiumMembership" | i18n }}
|
{{ "premiumMembership" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content box-content-padded">
|
<div class="box-content box-content-padded">
|
||||||
<div *ngIf="!isPremium">
|
<div *ngIf="!isPremium">
|
||||||
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
|
<p class="text-center lead">{{ "premiumNotCurrentMember" | i18n }}</p>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<div class="modal fade" role="dialog" aria-modal="true" attr.aria-label="{{ 'settings' | i18n }}">
|
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="settingsTitle">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body form">
|
<div class="modal-body form">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h1 class="box-header" id="settingsTitle">
|
||||||
{{ "settingsTitle" | i18n: currentUserEmail }}
|
{{ "settingsTitle" | i18n: currentUserEmail }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content box-content-padded">
|
<div class="box-content box-content-padded">
|
||||||
<h2>
|
<h2>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="twoStepTitle">
|
<h1 class="box-header" id="twoStepTitle">
|
||||||
{{ "twoStepOptions" | i18n }}
|
{{ "twoStepOptions" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<div class="modal fade" role="dialog" aria-modal="true">
|
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="passwordConfirmationTitle">
|
||||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||||
<form class="modal-content" #form (ngSubmit)="submit()">
|
<form class="modal-content" #form (ngSubmit)="submit()">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">{{ "passwordConfirmation" | i18n }}</div>
|
<h1 class="box-header" id="passwordConfirmationTitle">
|
||||||
|
{{ "passwordConfirmation" | i18n }}
|
||||||
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
</app-callout>
|
</app-callout>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="name">{{ "name" | i18n }}</label>
|
<label for="name">{{ "name" | i18n }}</label>
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="toggle"
|
class="toggle"
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
[ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }"
|
[ngClass]="{ 'bwi-angle-down': !showOptions, 'bwi-chevron-up': showOptions }"
|
||||||
></i>
|
></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div [hidden]="!showOptions">
|
<div [hidden]="!showOptions">
|
||||||
<app-send-efflux-dates
|
<app-send-efflux-dates
|
||||||
@@ -179,9 +179,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "notes" | i18n }}
|
{{ "notes" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -227,9 +227,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "share" | i18n }}
|
{{ "share" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
<div class="box-content-row" appBoxRow *ngIf="editMode">
|
||||||
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
<label for="link">{{ "sendLinkLabel" | i18n }}</label>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "customFields" | i18n }}
|
{{ "customFields" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields">
|
<div cdkDropList (cdkDropListDropped)="drop($event)" *ngIf="cipher.hasFields">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
<app-callout type="info" *ngIf="allowOwnershipOptions() && !allowPersonal">
|
<app-callout type="info" *ngIf="allowOwnershipOptions() && !allowPersonal">
|
||||||
{{ "personalOwnershipPolicyInEffect" | i18n }}
|
{{ "personalOwnershipPolicyInEffect" | i18n }}
|
||||||
</app-callout>
|
</app-callout>
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
|
||||||
<label for="type">{{ "type" | i18n }}</label>
|
<label for="type">{{ "type" | i18n }}</label>
|
||||||
@@ -504,9 +504,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
<label for="notes">{{ "notes" | i18n }}</label>
|
<label for="notes">{{ "notes" | i18n }}</label>
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
|
<textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
|
||||||
@@ -520,9 +520,9 @@
|
|||||||
>
|
>
|
||||||
</app-vault-add-edit-custom-fields>
|
</app-vault-add-edit-custom-fields>
|
||||||
<div class="box" *ngIf="allowOwnershipOptions()">
|
<div class="box" *ngIf="allowOwnershipOptions()">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "ownership" | i18n }}
|
{{ "ownership" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="organizationId">{{ "whoOwnsThisItem" | i18n }}</label>
|
<label for="organizationId">{{ "whoOwnsThisItem" | i18n }}</label>
|
||||||
@@ -539,9 +539,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="(!editMode || cloneMode) && cipher.organizationId">
|
<div class="box" *ngIf="(!editMode || cloneMode) && cipher.organizationId">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "collections" | i18n }}
|
{{ "collections" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content" *ngIf="!collections || !collections.length">
|
<div class="box-content" *ngIf="!collections || !collections.length">
|
||||||
{{ "noCollectionsInList" | i18n }}
|
{{ "noCollectionsInList" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box" *ngIf="cipher && cipher.hasAttachments">
|
<div class="box" *ngIf="cipher && cipher.hasAttachments">
|
||||||
<div class="box-header" id="attachmentsTitle">
|
<h1 class="box-header" id="attachmentsTitle">
|
||||||
{{ "attachments" | i18n }}
|
{{ "attachments" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content no-hover">
|
<div class="box-content no-hover">
|
||||||
<div class="box-content-row box-content-row-flex" *ngFor="let a of cipher.attachments">
|
<div class="box-content-row box-content-row-flex" *ngFor="let a of cipher.attachments">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
@@ -39,9 +39,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "newAttachment" | i18n }}
|
{{ "newAttachment" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content no-hover">
|
<div class="box-content no-hover">
|
||||||
<div class="box-content-row">
|
<div class="box-content-row">
|
||||||
<label for="file">{{ "file" | i18n }}</label>
|
<label for="file">{{ "file" | i18n }}</label>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="collectionsTitle">
|
<h1 class="box-header" id="collectionsTitle">
|
||||||
{{ "collections" | i18n }}
|
{{ "collections" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content" *ngIf="!collections || !collections.length">
|
<div class="box-content" *ngIf="!collections || !collections.length">
|
||||||
{{ "noCollectionsInList" | i18n }}
|
{{ "noCollectionsInList" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
</app-callout>
|
</app-callout>
|
||||||
<app-export-scope-callout *ngIf="!disabledByPolicy"></app-export-scope-callout>
|
<app-export-scope-callout *ngIf="!disabledByPolicy"></app-export-scope-callout>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="exportTitle">
|
<h1 class="box-header" id="exportTitle">
|
||||||
{{ "exportVault" | i18n }}
|
{{ "exportVault" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="format">{{ "fileFormat" | i18n }}</label>
|
<label for="format">{{ "fileFormat" | i18n }}</label>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="folderAddEditTitle">
|
<h1 class="box-header" id="folderAddEditTitle">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row" appBoxRow>
|
<div class="box-content-row" appBoxRow>
|
||||||
<label for="name">{{ "name" | i18n }}</label>
|
<label for="name">{{ "name" | i18n }}</label>
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
<div
|
<div class="modal fade" role="dialog" aria-modal="true" aria-labelledby="generatorTitle">
|
||||||
class="modal fade"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
attr.aria-label="{{ 'generatePassword' | i18n }}"
|
|
||||||
>
|
|
||||||
<div class="modal-dialog modal-md" role="document">
|
<div class="modal-dialog modal-md" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="modal-title">
|
<h1 class="modal-title" id="generatorTitle">
|
||||||
{{ "generator" | i18n }}
|
{{ "generator" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<app-callout
|
<app-callout
|
||||||
type="info"
|
type="info"
|
||||||
*ngIf="enforcedPasswordPolicyOptions?.inEffect() && type === 'password'"
|
*ngIf="enforcedPasswordPolicyOptions?.inEffect() && type === 'password'"
|
||||||
@@ -103,7 +98,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="type === 'password'">
|
<ng-container *ngIf="type === 'password'">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="toggleOptions()"
|
(click)="toggleOptions()"
|
||||||
@@ -114,7 +109,7 @@
|
|||||||
<i class="bwi bwi-minus-square" aria-hidden="true" [hidden]="!showOptions"></i>
|
<i class="bwi bwi-minus-square" aria-hidden="true" [hidden]="!showOptions"></i>
|
||||||
{{ "options" | i18n }}
|
{{ "options" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content condensed" [hidden]="!showOptions">
|
<div class="box-content condensed" [hidden]="!showOptions">
|
||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-radio"
|
class="box-content-row box-content-row-radio"
|
||||||
@@ -303,7 +298,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="type === 'username'">
|
<ng-container *ngIf="type === 'username'">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
(click)="toggleOptions()"
|
(click)="toggleOptions()"
|
||||||
@@ -314,7 +309,7 @@
|
|||||||
<i class="bwi bwi-minus-square" aria-hidden="true" [hidden]="!showOptions"></i>
|
<i class="bwi bwi-minus-square" aria-hidden="true" [hidden]="!showOptions"></i>
|
||||||
{{ "options" | i18n }}
|
{{ "options" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content condensed" [hidden]="!showOptions">
|
<div class="box-content condensed" [hidden]="!showOptions">
|
||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-radio"
|
class="box-content-row box-content-row-radio"
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="passwordGenHistoryTitle">
|
<h1 class="box-header" id="passwordGenHistoryTitle">
|
||||||
{{ "passwordHistory" | i18n }}
|
{{ "passwordHistory" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content condensed">
|
<div class="box-content condensed">
|
||||||
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="passwordHistoryTitle">
|
<h1 class="box-header" id="passwordHistoryTitle">
|
||||||
{{ "passwordHistory" | i18n }}
|
{{ "passwordHistory" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content condensed">
|
<div class="box-content condensed">
|
||||||
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
<div class="box-content-row box-content-row-flex" *ngFor="let h of history">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header" id="moveToOrgTitle">
|
<h1 class="box-header" id="moveToOrgTitle">
|
||||||
{{ "moveToOrganization" | i18n }}
|
{{ "moveToOrganization" | i18n }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="box-content" *ngIf="!organizations || !organizations.length">
|
<div class="box-content" *ngIf="!organizations || !organizations.length">
|
||||||
<div class="box-content-row">
|
<div class="box-content-row">
|
||||||
{{ "noOrganizationsList" | i18n }}
|
{{ "noOrganizationsList" | i18n }}
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="organizations && organizations.length">
|
<div class="box" *ngIf="organizations && organizations.length">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "collections" | i18n }}
|
{{ "collections" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content" *ngIf="!collections || !collections.length">
|
<div class="box-content" *ngIf="!collections || !collections.length">
|
||||||
{{ "noCollectionsInList" | i18n }}
|
{{ "noCollectionsInList" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "customFields" | i18n }}
|
{{ "customFields" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row box-content-row-flex" *ngFor="let field of cipher.fields">
|
<div class="box-content-row box-content-row-flex" *ngFor="let field of cipher.fields">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="inner-content" *ngIf="cipher">
|
<div class="inner-content" *ngIf="cipher">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "itemInformation" | i18n }}
|
{{ "itemInformation" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row">
|
<div class="box-content-row">
|
||||||
<span class="row-label">{{ "name" | i18n }}</span>
|
<span class="row-label">{{ "name" | i18n }}</span>
|
||||||
@@ -321,9 +321,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box" *ngIf="cipher.notes">
|
<div class="box" *ngIf="cipher.notes">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "notes" | i18n }}
|
{{ "notes" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<div class="box-content-row pre-wrap">{{ cipher.notes }}</div>
|
<div class="box-content-row pre-wrap">{{ cipher.notes }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -336,9 +336,9 @@
|
|||||||
>
|
>
|
||||||
</app-vault-view-custom-fields>
|
</app-vault-view-custom-fields>
|
||||||
<div class="box" *ngIf="cipher.hasAttachments && (canAccessPremium || cipher.organizationId)">
|
<div class="box" *ngIf="cipher.hasAttachments && (canAccessPremium || cipher.organizationId)">
|
||||||
<div class="box-header">
|
<h2 class="box-header">
|
||||||
{{ "attachments" | i18n }}
|
{{ "attachments" | i18n }}
|
||||||
</div>
|
</h2>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
4
apps/desktop/src/package-lock.json
generated
4
apps/desktop/src/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "2022.8.1",
|
"version": "2022.8.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "2022.8.1",
|
"version": "2022.8.2",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bitwarden/desktop-native": "file:../desktop_native"
|
"@bitwarden/desktop-native": "file:../desktop_native"
|
||||||
|
|||||||
@@ -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": "2022.8.1",
|
"version": "2022.8.2",
|
||||||
"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",
|
||||||
|
|||||||
@@ -31,10 +31,8 @@ h4,
|
|||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: $font-family-sans-serif;
|
font-family: $font-family-sans-serif;
|
||||||
|
font-size: $font-size-base;
|
||||||
@include themify($themes) {
|
font-weight: normal;
|
||||||
color: themed("textColor");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus-visible,
|
||||||
&.active {
|
&.active {
|
||||||
@include themify($themes) {
|
@include themify($themes) {
|
||||||
background-color: themed("boxBackgroundHoverColor");
|
background-color: themed("boxBackgroundHoverColor");
|
||||||
@@ -77,6 +77,10 @@
|
|||||||
|
|
||||||
&.box-content-padded {
|
&.box-content-padded {
|
||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
|
|
||||||
|
.box-header-expandable[aria-expanded="true"] {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.condensed .box-content-row,
|
&.condensed .box-content-row,
|
||||||
@@ -343,7 +347,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:not([type="file"]):focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
|
<button type="submit" class="btn btn-primary btn-submit">
|
||||||
<span>{{ "ok" | i18n }}</span>
|
<span>{{ "ok" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h2 class="modal-title" title="2faDuoTitle">
|
<h2 class="modal-title" id="2faDuoTitle">
|
||||||
{{ "twoStepLogin" | i18n }}
|
{{ "twoStepLogin" | i18n }}
|
||||||
<small>Duo</small>
|
<small>Duo</small>
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { Directive, ElementRef, HostListener } from "@angular/core";
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: "[appBlurClick]",
|
|
||||||
})
|
|
||||||
export class BlurClickDirective {
|
|
||||||
constructor(private el: ElementRef) {}
|
|
||||||
|
|
||||||
@HostListener("click") onClick() {
|
|
||||||
this.el.nativeElement.blur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,6 @@ import { A11yInvalidDirective } from "./directives/a11y-invalid.directive";
|
|||||||
import { A11yTitleDirective } from "./directives/a11y-title.directive";
|
import { A11yTitleDirective } from "./directives/a11y-title.directive";
|
||||||
import { ApiActionDirective } from "./directives/api-action.directive";
|
import { ApiActionDirective } from "./directives/api-action.directive";
|
||||||
import { AutofocusDirective } from "./directives/autofocus.directive";
|
import { AutofocusDirective } from "./directives/autofocus.directive";
|
||||||
import { BlurClickDirective } from "./directives/blur-click.directive";
|
|
||||||
import { BoxRowDirective } from "./directives/box-row.directive";
|
import { BoxRowDirective } from "./directives/box-row.directive";
|
||||||
import { FallbackSrcDirective } from "./directives/fallback-src.directive";
|
import { FallbackSrcDirective } from "./directives/fallback-src.directive";
|
||||||
import { InputStripSpacesDirective } from "./directives/input-strip-spaces.directive";
|
import { InputStripSpacesDirective } from "./directives/input-strip-spaces.directive";
|
||||||
@@ -48,7 +47,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
|
|||||||
ApiActionDirective,
|
ApiActionDirective,
|
||||||
AutofocusDirective,
|
AutofocusDirective,
|
||||||
AvatarComponent,
|
AvatarComponent,
|
||||||
BlurClickDirective,
|
|
||||||
BoxRowDirective,
|
BoxRowDirective,
|
||||||
CalloutComponent,
|
CalloutComponent,
|
||||||
ColorPasswordCountPipe,
|
ColorPasswordCountPipe,
|
||||||
@@ -78,7 +76,6 @@ import { PasswordStrengthComponent } from "./shared/components/password-strength
|
|||||||
AutofocusDirective,
|
AutofocusDirective,
|
||||||
AvatarComponent,
|
AvatarComponent,
|
||||||
BitwardenToastModule,
|
BitwardenToastModule,
|
||||||
BlurClickDirective,
|
|
||||||
BoxRowDirective,
|
BoxRowDirective,
|
||||||
CalloutComponent,
|
CalloutComponent,
|
||||||
ColorPasswordCountPipe,
|
ColorPasswordCountPipe,
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -221,7 +221,7 @@
|
|||||||
},
|
},
|
||||||
"apps/desktop": {
|
"apps/desktop": {
|
||||||
"name": "@bitwarden/desktop",
|
"name": "@bitwarden/desktop",
|
||||||
"version": "2022.8.1",
|
"version": "2022.8.2",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "GPL-3.0"
|
"license": "GPL-3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user