mirror of
https://github.com/bitwarden/browser
synced 2026-02-23 16:13:21 +00:00
Merge branch 'main' into ps/extension-refresh
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@bitwarden/desktop",
|
||||
"description": "A secure and free password manager for all of your devices.",
|
||||
"version": "2024.4.3",
|
||||
"version": "2024.5.0",
|
||||
"keywords": [
|
||||
"bitwarden",
|
||||
"password",
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { BehaviorSubject, firstValueFrom, Observable, Subject } from "rxjs";
|
||||
import { BehaviorSubject, Observable, Subject, firstValueFrom } from "rxjs";
|
||||
import { concatMap, debounceTime, filter, map, switchMap, takeUntil, tap } from "rxjs/operators";
|
||||
|
||||
import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { AuthRequestServiceAbstraction, PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
@@ -19,10 +20,15 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
||||
import { ThemeType, KeySuffixOptions } from "@bitwarden/common/platform/enums";
|
||||
import { KeySuffixOptions, ThemeType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
VaultTimeout,
|
||||
VaultTimeoutOption,
|
||||
VaultTimeoutStringType,
|
||||
} from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { SetPinComponent } from "../../auth/components/set-pin.component";
|
||||
@@ -40,7 +46,7 @@ export class SettingsComponent implements OnInit {
|
||||
protected readonly VaultTimeoutAction = VaultTimeoutAction;
|
||||
|
||||
showMinToTray = false;
|
||||
vaultTimeoutOptions: any[];
|
||||
vaultTimeoutOptions: VaultTimeoutOption[];
|
||||
localeOptions: any[];
|
||||
themeOptions: any[];
|
||||
clearClipboardOptions: any[];
|
||||
@@ -71,14 +77,14 @@ export class SettingsComponent implements OnInit {
|
||||
timeout: { hours: number; minutes: number };
|
||||
action: "lock" | "logOut";
|
||||
}>;
|
||||
previousVaultTimeout: number = null;
|
||||
previousVaultTimeout: VaultTimeout = null;
|
||||
|
||||
userHasMasterPassword: boolean;
|
||||
userHasPinSet: boolean;
|
||||
|
||||
form = this.formBuilder.group({
|
||||
// Security
|
||||
vaultTimeout: [null as number | null],
|
||||
vaultTimeout: [null as VaultTimeout | null],
|
||||
vaultTimeoutAction: [VaultTimeoutAction.Lock],
|
||||
pin: [null as boolean | null],
|
||||
biometric: false,
|
||||
@@ -111,6 +117,7 @@ export class SettingsComponent implements OnInit {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private policyService: PolicyService,
|
||||
private formBuilder: FormBuilder,
|
||||
private i18nService: I18nService,
|
||||
@@ -127,6 +134,7 @@ export class SettingsComponent implements OnInit {
|
||||
private desktopSettingsService: DesktopSettingsService,
|
||||
private biometricStateService: BiometricStateService,
|
||||
private desktopAutofillSettingsService: DesktopAutofillSettingsService,
|
||||
private pinService: PinServiceAbstraction,
|
||||
private authRequestService: AuthRequestServiceAbstraction,
|
||||
private logService: LogService,
|
||||
private nativeMessagingManifestService: NativeMessagingManifestService,
|
||||
@@ -156,24 +164,26 @@ export class SettingsComponent implements OnInit {
|
||||
this.showDuckDuckGoIntegrationOption = isMac;
|
||||
|
||||
this.vaultTimeoutOptions = [
|
||||
// { name: i18nService.t('immediately'), value: 0 },
|
||||
{ name: this.i18nService.t("oneMinute"), value: 1 },
|
||||
{ name: this.i18nService.t("fiveMinutes"), value: 5 },
|
||||
{ name: this.i18nService.t("fifteenMinutes"), value: 15 },
|
||||
{ name: this.i18nService.t("thirtyMinutes"), value: 30 },
|
||||
{ name: this.i18nService.t("oneHour"), value: 60 },
|
||||
{ name: this.i18nService.t("fourHours"), value: 240 },
|
||||
{ name: this.i18nService.t("onIdle"), value: -4 },
|
||||
{ name: this.i18nService.t("onSleep"), value: -3 },
|
||||
{ name: this.i18nService.t("onIdle"), value: VaultTimeoutStringType.OnIdle },
|
||||
{ name: this.i18nService.t("onSleep"), value: VaultTimeoutStringType.OnSleep },
|
||||
];
|
||||
|
||||
if (this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop) {
|
||||
this.vaultTimeoutOptions.push({ name: this.i18nService.t("onLocked"), value: -2 });
|
||||
this.vaultTimeoutOptions.push({
|
||||
name: this.i18nService.t("onLocked"),
|
||||
value: VaultTimeoutStringType.OnLocked,
|
||||
});
|
||||
}
|
||||
|
||||
this.vaultTimeoutOptions = this.vaultTimeoutOptions.concat([
|
||||
{ name: this.i18nService.t("onRestart"), value: -1 },
|
||||
{ name: this.i18nService.t("never"), value: null },
|
||||
{ name: this.i18nService.t("onRestart"), value: VaultTimeoutStringType.OnRestart },
|
||||
{ name: this.i18nService.t("never"), value: VaultTimeoutStringType.Never },
|
||||
]);
|
||||
|
||||
const localeOptions: any[] = [];
|
||||
@@ -243,14 +253,19 @@ export class SettingsComponent implements OnInit {
|
||||
}),
|
||||
);
|
||||
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
|
||||
// Load initial values
|
||||
const pinStatus = await this.vaultTimeoutSettingsService.isPinLockSet();
|
||||
this.userHasPinSet = pinStatus !== "DISABLED";
|
||||
this.userHasPinSet = await this.pinService.isPinSet(userId);
|
||||
|
||||
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
const initialValues = {
|
||||
vaultTimeout: await this.vaultTimeoutSettingsService.getVaultTimeout(),
|
||||
vaultTimeout: await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(activeAccount.id),
|
||||
),
|
||||
vaultTimeoutAction: await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService.vaultTimeoutAction$(),
|
||||
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
|
||||
),
|
||||
pin: this.userHasPinSet,
|
||||
biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(),
|
||||
@@ -295,7 +310,9 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
this.refreshTimeoutSettings$
|
||||
.pipe(
|
||||
switchMap(() => this.vaultTimeoutSettingsService.vaultTimeoutAction$()),
|
||||
switchMap(() =>
|
||||
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
|
||||
),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe((action) => {
|
||||
@@ -353,8 +370,8 @@ export class SettingsComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
async saveVaultTimeout(newValue: number) {
|
||||
if (newValue == null) {
|
||||
async saveVaultTimeout(newValue: VaultTimeout) {
|
||||
if (newValue === VaultTimeoutStringType.Never) {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "warning" },
|
||||
content: { key: "neverLockWarning" },
|
||||
@@ -383,7 +400,10 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
this.previousVaultTimeout = this.form.value.vaultTimeout;
|
||||
|
||||
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
|
||||
activeAccount.id,
|
||||
newValue,
|
||||
this.form.value.vaultTimeoutAction,
|
||||
);
|
||||
@@ -414,7 +434,10 @@ export class SettingsComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
|
||||
activeAccount.id,
|
||||
this.form.value.vaultTimeout,
|
||||
newValue,
|
||||
);
|
||||
|
||||
@@ -38,9 +38,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { SystemService } from "@bitwarden/common/platform/abstractions/system.service";
|
||||
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
||||
import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize";
|
||||
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { VaultTimeout, VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
@@ -64,12 +66,6 @@ const BroadcasterSubscriptionId = "AppComponent";
|
||||
const IdleTimeout = 60000 * 10; // 10 minutes
|
||||
const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours
|
||||
|
||||
const systemTimeoutOptions = {
|
||||
onLock: -2,
|
||||
onSuspend: -3,
|
||||
onIdle: -4,
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-root",
|
||||
styles: [],
|
||||
@@ -401,6 +397,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.router.navigate(["/remove-password"]);
|
||||
break;
|
||||
case "switchAccount": {
|
||||
// Clear sequentialized caches
|
||||
clearCaches();
|
||||
if (message.userId != null) {
|
||||
await this.stateService.clearDecryptedData(message.userId);
|
||||
await this.accountService.switchAccount(message.userId);
|
||||
@@ -430,13 +428,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
break;
|
||||
}
|
||||
case "systemSuspended":
|
||||
await this.checkForSystemTimeout(systemTimeoutOptions.onSuspend);
|
||||
await this.checkForSystemTimeout(VaultTimeoutStringType.OnSleep);
|
||||
break;
|
||||
case "systemLocked":
|
||||
await this.checkForSystemTimeout(systemTimeoutOptions.onLock);
|
||||
await this.checkForSystemTimeout(VaultTimeoutStringType.OnLocked);
|
||||
break;
|
||||
case "systemIdle":
|
||||
await this.checkForSystemTimeout(systemTimeoutOptions.onIdle);
|
||||
await this.checkForSystemTimeout(VaultTimeoutStringType.OnIdle);
|
||||
break;
|
||||
case "openLoginApproval":
|
||||
if (message.notificationId != null) {
|
||||
@@ -721,7 +719,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private async checkForSystemTimeout(timeout: number): Promise<void> {
|
||||
private async checkForSystemTimeout(timeout: VaultTimeout): Promise<void> {
|
||||
const accounts = await firstValueFrom(this.accountService.accounts$);
|
||||
for (const userId in accounts) {
|
||||
if (userId == null) {
|
||||
@@ -738,9 +736,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private async getVaultTimeoutOptions(userId: string): Promise<[number, string]> {
|
||||
const timeout = await this.stateService.getVaultTimeout({ userId: userId });
|
||||
const action = await this.stateService.getVaultTimeoutAction({ userId: userId });
|
||||
private async getVaultTimeoutOptions(userId: string): Promise<[VaultTimeout, string]> {
|
||||
const timeout = await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(userId),
|
||||
);
|
||||
const action = await firstValueFrom(
|
||||
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(userId),
|
||||
);
|
||||
return [timeout, action];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
SYSTEM_THEME_OBSERVABLE,
|
||||
SafeInjectionToken,
|
||||
STATE_FACTORY,
|
||||
DEFAULT_VAULT_TIMEOUT,
|
||||
INTRAPROCESS_MESSAGING_SUBJECT,
|
||||
CLIENT_TYPE,
|
||||
} from "@bitwarden/angular/services/injection-tokens";
|
||||
@@ -56,9 +57,11 @@ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/s
|
||||
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
|
||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { PinServiceAbstraction } from "../../../../../libs/auth/src/common/abstractions";
|
||||
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
|
||||
import { Account } from "../../models/account";
|
||||
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
||||
@@ -137,6 +140,10 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: SUPPORTS_SECURE_STORAGE,
|
||||
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
|
||||
}),
|
||||
safeProvider({
|
||||
provide: DEFAULT_VAULT_TIMEOUT,
|
||||
useValue: VaultTimeoutStringType.OnRestart,
|
||||
}),
|
||||
safeProvider({
|
||||
provide: I18nServiceAbstraction,
|
||||
useClass: I18nRendererService,
|
||||
@@ -183,6 +190,7 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: SystemServiceAbstraction,
|
||||
useClass: SystemService,
|
||||
deps: [
|
||||
PinServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
RELOAD_CALLBACK,
|
||||
@@ -250,6 +258,7 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: CryptoServiceAbstraction,
|
||||
useClass: ElectronCryptoService,
|
||||
deps: [
|
||||
PinServiceAbstraction,
|
||||
InternalMasterPasswordServiceAbstraction,
|
||||
KeyGenerationServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
|
||||
@@ -12,8 +12,16 @@
|
||||
<input class="tw-font-mono" bitInput type="password" formControlName="pin" />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
</bit-form-field>
|
||||
<label class="tw-flex tw-items-start tw-gap-2" *ngIf="showMasterPassOnRestart">
|
||||
<input class="tw-mt-1" type="checkbox" bitCheckbox formControlName="masterPassOnRestart" />
|
||||
<label
|
||||
class="tw-flex tw-items-start tw-gap-2"
|
||||
*ngIf="showMasterPasswordOnClientRestartOption"
|
||||
>
|
||||
<input
|
||||
class="tw-mt-1"
|
||||
type="checkbox"
|
||||
bitCheckbox
|
||||
formControlName="requireMasterPasswordOnClientRestart"
|
||||
/>
|
||||
<span>{{ "lockWithMasterPassOnRestart" | i18n }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { of } from "rxjs";
|
||||
|
||||
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { PinCryptoServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
@@ -155,8 +155,8 @@ describe("LockComponent", () => {
|
||||
useValue: mock<UserVerificationService>(),
|
||||
},
|
||||
{
|
||||
provide: PinCryptoServiceAbstraction,
|
||||
useValue: mock<PinCryptoServiceAbstraction>(),
|
||||
provide: PinServiceAbstraction,
|
||||
useValue: mock<PinServiceAbstraction>(),
|
||||
},
|
||||
{
|
||||
provide: BiometricStateService,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom, switchMap } from "rxjs";
|
||||
|
||||
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
||||
import { PinCryptoServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
@@ -62,7 +62,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
dialogService: DialogService,
|
||||
deviceTrustService: DeviceTrustServiceAbstraction,
|
||||
userVerificationService: UserVerificationService,
|
||||
pinCryptoService: PinCryptoServiceAbstraction,
|
||||
pinService: PinServiceAbstraction,
|
||||
biometricStateService: BiometricStateService,
|
||||
accountService: AccountService,
|
||||
authService: AuthService,
|
||||
@@ -88,7 +88,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
dialogService,
|
||||
deviceTrustService,
|
||||
userVerificationService,
|
||||
pinCryptoService,
|
||||
pinService,
|
||||
biometricStateService,
|
||||
accountService,
|
||||
authService,
|
||||
|
||||
@@ -2132,6 +2132,108 @@
|
||||
"forwardedEmailDesc": {
|
||||
"message": "Generate an email alias with an external forwarding service."
|
||||
},
|
||||
"forwarderError": {
|
||||
"message": "$SERVICENAME$ error: $ERRORMESSAGE$",
|
||||
"description": "Reports an error returned by a forwarding service to the user.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
},
|
||||
"errormessage": {
|
||||
"content": "$2",
|
||||
"example": "Invalid characters in domain name."
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderGeneratedBy": {
|
||||
"message": "Generated by Bitwarden.",
|
||||
"description": "Displayed with the address on the forwarding service's configuration screen."
|
||||
},
|
||||
"forwarderGeneratedByWithWebsite": {
|
||||
"message": "Website: $WEBSITE$. Generated by Bitwarden.",
|
||||
"description": "Displayed with the address on the forwarding service's configuration screen.",
|
||||
"placeholders": {
|
||||
"WEBSITE": {
|
||||
"content": "$1",
|
||||
"example": "www.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwaderInvalidToken": {
|
||||
"message": "Invalid $SERVICENAME$ API token",
|
||||
"description": "Displayed when the user's API token is empty or rejected by the forwarding service.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwaderInvalidTokenWithMessage": {
|
||||
"message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$",
|
||||
"description": "Displayed when the user's API token is rejected by the forwarding service with an error message.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
},
|
||||
"errormessage": {
|
||||
"content": "$2",
|
||||
"example": "Please verify your email address to continue."
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderNoAccountId": {
|
||||
"message": "Unable to obtain $SERVICENAME$ masked email account ID.",
|
||||
"description": "Displayed when the forwarding service fails to return an account ID.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderNoDomain": {
|
||||
"message": "Invalid $SERVICENAME$ domain.",
|
||||
"description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderNoUrl": {
|
||||
"message": "Invalid $SERVICENAME$ url.",
|
||||
"description": "Displayed when the url of the forwarding service wasn't supplied.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderUnknownError": {
|
||||
"message": "Unknown $SERVICENAME$ error occurred.",
|
||||
"description": "Displayed when the forwarding service failed due to an unknown error.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "SimpleLogin"
|
||||
}
|
||||
}
|
||||
},
|
||||
"forwarderUnknownForwarder": {
|
||||
"message": "Unknown forwarder: '$SERVICENAME$'.",
|
||||
"description": "Displayed when the forwarding service is not supported.",
|
||||
"placeholders": {
|
||||
"servicename": {
|
||||
"content": "$1",
|
||||
"example": "JustTrust.us"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hostname": {
|
||||
"message": "Hostname",
|
||||
"description": "Part of a URL."
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
"message": "El tamaño máximo de archivo es de 500MB."
|
||||
},
|
||||
"encryptionKeyMigrationRequired": {
|
||||
"message": "Encryption key migration required. Please login through the web vault to update your encryption key."
|
||||
"message": "Se requiere migración de la clave de cifrado. Por favor, inicia sesión a través de la caja fuerte web para actualizar su clave de cifrado."
|
||||
},
|
||||
"editedFolder": {
|
||||
"message": "Carpeta editada"
|
||||
@@ -561,10 +561,10 @@
|
||||
"message": "¡Tu nueva cuenta ha sido creada! Ahora puedes acceder."
|
||||
},
|
||||
"youSuccessfullyLoggedIn": {
|
||||
"message": "You successfully logged in"
|
||||
"message": "Has iniciado sesión correctamente"
|
||||
},
|
||||
"youMayCloseThisWindow": {
|
||||
"message": "You may close this window"
|
||||
"message": "Puedes cerrar esta ventana"
|
||||
},
|
||||
"masterPassSent": {
|
||||
"message": "Te hemos enviado un correo electrónico con la pista de tu contraseña maestra."
|
||||
@@ -801,10 +801,10 @@
|
||||
"message": "Cambiar contraseña maestra"
|
||||
},
|
||||
"continueToWebApp": {
|
||||
"message": "Continue to web app?"
|
||||
"message": "¿Continuar a la aplicación web?"
|
||||
},
|
||||
"changeMasterPasswordOnWebConfirmation": {
|
||||
"message": "You can change your master password on the Bitwarden web app."
|
||||
"message": "Puedes cambiar tu contraseña maestra en la aplicación web de Bitwarden."
|
||||
},
|
||||
"fingerprintPhrase": {
|
||||
"message": "Frase de huella digital",
|
||||
@@ -1090,7 +1090,7 @@
|
||||
"message": "1GB de espacio en disco cifrado."
|
||||
},
|
||||
"premiumSignUpTwoStepOptions": {
|
||||
"message": "Proprietary two-step login options such as YubiKey and Duo."
|
||||
"message": "Opciones de inicio de sesión con autenticación de dos pasos propietarios como YubiKey y Duo."
|
||||
},
|
||||
"premiumSignUpReports": {
|
||||
"message": "Higiene de contraseña, salud de la cuenta e informes de violaciones de datos para mantener tu caja fuerte segura."
|
||||
@@ -1402,7 +1402,7 @@
|
||||
"message": "Código PIN inválido."
|
||||
},
|
||||
"tooManyInvalidPinEntryAttemptsLoggingOut": {
|
||||
"message": "Too many invalid PIN entry attempts. Logging out."
|
||||
"message": "Demasiados intentos de entrada de PIN no válidos. Cerrando sesión."
|
||||
},
|
||||
"unlockWithWindowsHello": {
|
||||
"message": "Desbloquear con Windows Hello"
|
||||
@@ -1553,11 +1553,11 @@
|
||||
"description": "Used as a card title description on the set password page to explain why the user is there"
|
||||
},
|
||||
"orgRequiresYouToSetPassword": {
|
||||
"message": "Your organization requires you to set a master password.",
|
||||
"message": "Tu organización requiere que establezcas una contraseña maestra.",
|
||||
"description": "Used as a card title description on the set password page to explain why the user is there"
|
||||
},
|
||||
"verificationRequired": {
|
||||
"message": "Verification required",
|
||||
"message": "Verificación requerida",
|
||||
"description": "Default title for the user verification dialog."
|
||||
},
|
||||
"currentMasterPass": {
|
||||
@@ -1633,10 +1633,10 @@
|
||||
"message": "La integración con el navegador no está soportada"
|
||||
},
|
||||
"browserIntegrationErrorTitle": {
|
||||
"message": "Error enabling browser integration"
|
||||
"message": "Error al habilitar la integración del navegador"
|
||||
},
|
||||
"browserIntegrationErrorDesc": {
|
||||
"message": "An error has occurred while enabling browser integration."
|
||||
"message": "Se ha producido un error mientras se habilitaba la integración del navegador."
|
||||
},
|
||||
"browserIntegrationMasOnlyDesc": {
|
||||
"message": "Por desgracia la integración del navegador sólo está soportada por ahora en la versión de la Mac App Store."
|
||||
@@ -1654,7 +1654,7 @@
|
||||
"message": "Requiere una capa adicional de seguridad mediante el solicitar la frase de validación de huella dactilar al establecer un enlace entre el escritorio y el navegador. Cuando se activa, requiere intervención del usuario y verificación cada vez que se establece una conexión."
|
||||
},
|
||||
"enableHardwareAcceleration": {
|
||||
"message": "Use hardware acceleration"
|
||||
"message": "Utilizar aceleración de hardware"
|
||||
},
|
||||
"enableHardwareAccelerationDesc": {
|
||||
"message": "By default this setting is ON. Turn OFF only if you experience graphical issues. Restart is required."
|
||||
@@ -1898,16 +1898,16 @@
|
||||
"message": "Su contraseña maestra no cumple con una o más de las políticas de su organización. Para acceder a la caja fuerte, debe actualizar su contraseña maestra ahora. Proceder le desconectará de su sesión actual, requiriendo que vuelva a iniciar sesión. Las sesiones activas en otros dispositivos pueden seguir estando activas durante hasta una hora."
|
||||
},
|
||||
"tryAgain": {
|
||||
"message": "Try again"
|
||||
"message": "Intentar de nuevo"
|
||||
},
|
||||
"verificationRequiredForActionSetPinToContinue": {
|
||||
"message": "Verification required for this action. Set a PIN to continue."
|
||||
},
|
||||
"setPin": {
|
||||
"message": "Set PIN"
|
||||
"message": "Establecer PIN"
|
||||
},
|
||||
"verifyWithBiometrics": {
|
||||
"message": "Verify with biometrics"
|
||||
"message": "Verificar biométricamente"
|
||||
},
|
||||
"awaitingConfirmation": {
|
||||
"message": "Awaiting confirmation"
|
||||
|
||||
@@ -2698,7 +2698,7 @@
|
||||
"description": "Label indicating the most common import formats"
|
||||
},
|
||||
"success": {
|
||||
"message": "Success"
|
||||
"message": "Успех"
|
||||
},
|
||||
"troubleshooting": {
|
||||
"message": "Решавање проблема"
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
} from "@bitwarden/common/platform/models/domain/account";
|
||||
|
||||
export class AccountSettings extends BaseAccountSettings {
|
||||
vaultTimeout = -1; // On Restart
|
||||
dismissedBiometricRequirePasswordOnStartCallout?: boolean;
|
||||
}
|
||||
|
||||
|
||||
4
apps/desktop/src/package-lock.json
generated
4
apps/desktop/src/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@bitwarden/desktop",
|
||||
"version": "2024.4.3",
|
||||
"version": "2024.5.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@bitwarden/desktop",
|
||||
"version": "2024.4.3",
|
||||
"version": "2024.5.0",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@bitwarden/desktop-native": "file:../desktop_native",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@bitwarden/desktop",
|
||||
"productName": "Bitwarden",
|
||||
"description": "A secure and free password manager for all of your devices.",
|
||||
"version": "2024.4.3",
|
||||
"version": "2024.5.0",
|
||||
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
|
||||
"homepage": "https://bitwarden.com",
|
||||
"license": "GPL-3.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
@@ -26,6 +27,7 @@ import { ElectronCryptoService } from "./electron-crypto.service";
|
||||
describe("electronCryptoService", () => {
|
||||
let sut: ElectronCryptoService;
|
||||
|
||||
const pinService = mock<PinServiceAbstraction>();
|
||||
const keyGenerationService = mock<KeyGenerationService>();
|
||||
const cryptoFunctionService = mock<CryptoFunctionService>();
|
||||
const encryptService = mock<EncryptService>();
|
||||
@@ -46,6 +48,7 @@ describe("electronCryptoService", () => {
|
||||
stateProvider = new FakeStateProvider(accountService);
|
||||
|
||||
sut = new ElectronCryptoService(
|
||||
pinService,
|
||||
masterPasswordService,
|
||||
keyGenerationService,
|
||||
cryptoFunctionService,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
@@ -22,6 +23,7 @@ import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||
|
||||
export class ElectronCryptoService extends CryptoService {
|
||||
constructor(
|
||||
pinService: PinServiceAbstraction,
|
||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
keyGenerationService: KeyGenerationService,
|
||||
cryptoFunctionService: CryptoFunctionService,
|
||||
@@ -35,6 +37,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
pinService,
|
||||
masterPasswordService,
|
||||
keyGenerationService,
|
||||
cryptoFunctionService,
|
||||
@@ -89,7 +92,9 @@ export class ElectronCryptoService extends CryptoService {
|
||||
if (keySuffix === KeySuffixOptions.Biometric) {
|
||||
await this.migrateBiometricKeyIfNeeded(userId);
|
||||
const userKey = await this.stateService.getUserKeyBiometric({ userId: userId });
|
||||
return new SymmetricCryptoKey(Utils.fromB64ToArray(userKey)) as UserKey;
|
||||
return userKey == null
|
||||
? null
|
||||
: (new SymmetricCryptoKey(Utils.fromB64ToArray(userKey)) as UserKey);
|
||||
}
|
||||
return await super.getKeyFromStorage(keySuffix, userId);
|
||||
}
|
||||
@@ -166,7 +171,9 @@ export class ElectronCryptoService extends CryptoService {
|
||||
// decrypt
|
||||
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
|
||||
userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
const encUserKeyPrim = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||
const encUserKeyPrim = await this.stateService.getEncryptedCryptoSymmetricKey({
|
||||
userId: userId,
|
||||
});
|
||||
const encUserKey =
|
||||
encUserKeyPrim != null
|
||||
? new EncString(encUserKeyPrim)
|
||||
@@ -174,7 +181,11 @@ export class ElectronCryptoService extends CryptoService {
|
||||
if (!encUserKey) {
|
||||
throw new Error("No user key found during biometric migration");
|
||||
}
|
||||
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, encUserKey);
|
||||
const userKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(
|
||||
masterKey,
|
||||
encUserKey,
|
||||
userId,
|
||||
);
|
||||
// migrate
|
||||
await this.storeBiometricKey(userKey, userId);
|
||||
await this.stateService.setCryptoMasterKeyBiometric(null, { userId });
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.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";
|
||||
@@ -20,6 +21,7 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
organizationService: OrganizationService,
|
||||
logService: LogService,
|
||||
configService: ConfigService,
|
||||
) {
|
||||
super(
|
||||
collectionService,
|
||||
@@ -28,6 +30,7 @@ export class CollectionsComponent extends BaseCollectionsComponent {
|
||||
cipherService,
|
||||
organizationService,
|
||||
logService,
|
||||
configService,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user