1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-12 22:44:11 +00:00

Merge branch 'main' into ps/extension-refresh

This commit is contained in:
Victoria League
2024-10-29 10:16:16 -04:00
committed by GitHub
17 changed files with 102 additions and 67 deletions

View File

@@ -3234,9 +3234,6 @@
}
}
},
"loggingInOn": {
"message": "Logging in on"
},
"opensInANewWindow": {
"message": "Opens in a new window"
},

View File

@@ -57,7 +57,7 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
availableVaultTimeoutActions: VaultTimeoutAction[] = [];
vaultTimeoutOptions: VaultTimeoutOption[];
vaultTimeoutPolicyCallout: Observable<{
timeout: { hours: number; minutes: number };
timeout: { hours: string; minutes: string };
action: VaultTimeoutAction;
}>;
supportsBiometric: boolean;
@@ -105,8 +105,8 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
let timeout;
if (policy.data?.minutes) {
timeout = {
hours: Math.floor(policy.data?.minutes / 60),
minutes: policy.data?.minutes % 60,
hours: Math.floor(policy.data?.minutes / 60).toString(),
minutes: (policy.data?.minutes % 60).toString(),
};
}
return { timeout: timeout, action: policy.data?.action };

View File

@@ -629,6 +629,9 @@ describe("OverlayBackground", () => {
it("skips updating the inline menu list if the user has the inline menu set to open on button click", async () => {
inlineMenuVisibilityMock$.next(AutofillOverlayVisibility.OnButtonClick);
jest
.spyOn(overlayBackground as any, "checkIsInlineMenuListVisible")
.mockReturnValue(false);
tabsSendMessageSpy.mockImplementation((_tab, message, _options) => {
if (message.command === "checkFocusedFieldHasValue") {
return Promise.resolve(true);

View File

@@ -1009,7 +1009,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
this.logService.error(error),
);
if ((await this.getInlineMenuVisibility()) === AutofillOverlayVisibility.OnButtonClick) {
if (
!this.checkIsInlineMenuListVisible() &&
(await this.getInlineMenuVisibility()) === AutofillOverlayVisibility.OnButtonClick
) {
return;
}
@@ -2579,7 +2582,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
* @param sender
*/
private resetFocusedFieldSubFrameOffsets(sender: chrome.runtime.MessageSender) {
if (this.focusedFieldData.frameId > 0 && this.subFrameOffsetsForTab[sender.tab.id]) {
if (this.focusedFieldData?.frameId > 0 && this.subFrameOffsetsForTab[sender.tab.id]) {
this.subFrameOffsetsForTab[sender.tab.id].set(this.focusedFieldData.frameId, null);
}
}
@@ -2592,6 +2595,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
*/
private async triggerSubFrameFocusInRebuild(sender: chrome.runtime.MessageSender) {
this.cancelInlineMenuFadeInAndPositionUpdate();
this.resetFocusedFieldSubFrameOffsets(sender);
this.rebuildSubFrameOffsets$.next(sender);
this.repositionInlineMenu$.next(sender);
}

View File

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

View File

@@ -2804,9 +2804,6 @@
"message": "EU",
"description": "European Union"
},
"loggingInOn": {
"message": "Logging in on"
},
"selfHostedServer": {
"message": "self-hosted"
},

View File

@@ -1,12 +1,12 @@
{
"name": "@bitwarden/desktop",
"version": "2024.10.2",
"version": "2024.10.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/desktop",
"version": "2024.10.2",
"version": "2024.10.3",
"license": "GPL-3.0",
"dependencies": {
"@bitwarden/desktop-napi": "file:../desktop_native/napi",

View File

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

View File

@@ -1583,38 +1583,6 @@
"specialCharacters": {
"message": "Special characters (!@#$%^&*)"
},
"uppercaseDescription": {
"message": "Include uppercase characters",
"description": "Tooltip for the password generator uppercase character checkbox"
},
"uppercaseLabel": {
"message": "A-Z",
"description": "Label for the password generator uppercase character checkbox"
},
"lowercaseDescription": {
"message": "Include lowercase characters",
"description": "Full description for the password generator lowercase character checkbox"
},
"lowercaseLabel": {
"message": "a-z",
"description": "Label for the password generator lowercase character checkbox"
},
"numbersDescription": {
"message": "Include numbers",
"description": "Full description for the password generator numbers checkbox"
},
"numbersLabel": {
"message": "0-9",
"description": "Label for the password generator numbers checkbox"
},
"specialCharactersDescription": {
"message": "Include special characters",
"description": "Full description for the password generator special characters checkbox"
},
"specialCharactersLabel": {
"message": "!@#$%^&*",
"description": "Label for the password generator special characters checkbox"
},
"numWords": {
"message": "Number of words"
},
@@ -9529,10 +9497,6 @@
"message": "!@#$%^&*",
"description": "Label for the password generator special characters checkbox"
},
"avoidAmbiguous": {
"message": "Avoid ambiguous characters",
"description": "Label for the avoid ambiguous characters checkbox."
},
"addAttachment": {
"message": "Add attachment"
},

View File

@@ -4,7 +4,7 @@
} as data"
>
<div class="environment-selector-btn">
{{ "loggingInOn" | i18n }}:
{{ "accessing" | i18n }}:
<button
type="button"
(click)="toggle(null)"

View File

@@ -1,14 +1,19 @@
import { animate, state, style, transition, trigger } from "@angular/animations";
import { ConnectedPosition } from "@angular/cdk/overlay";
import { Component, EventEmitter, Output, Input, OnInit, OnDestroy } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import { ActivatedRoute } from "@angular/router";
import { Observable, map, Subject, takeUntil } from "rxjs";
import { SelfHostedEnvConfigDialogComponent } from "@bitwarden/auth/angular";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import {
EnvironmentService,
Region,
RegionConfig,
} from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService, ToastService } from "@bitwarden/components";
export const ExtensionDefaultOverlayPosition: ConnectedPosition[] = [
{
@@ -56,7 +61,7 @@ export interface EnvironmentSelectorRouteData {
],
})
export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
@Output() onOpenSelfHostedSettings = new EventEmitter();
@Output() onOpenSelfHostedSettings = new EventEmitter<void>();
@Input() overlayPosition: ConnectedPosition[] = [
{
originX: "start",
@@ -79,8 +84,11 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
constructor(
protected environmentService: EnvironmentService,
protected router: Router,
private route: ActivatedRoute,
private dialogService: DialogService,
private configService: ConfigService,
private toastService: ToastService,
private i18nService: I18nService,
) {}
ngOnInit() {
@@ -102,8 +110,25 @@ export class EnvironmentSelectorComponent implements OnInit, OnDestroy {
return;
}
/**
* Opens the self-hosted settings dialog.
*
* If the `UnauthenticatedExtensionUIRefresh` feature flag is enabled,
* the self-hosted settings dialog is opened directly. Otherwise, the
* `onOpenSelfHostedSettings` event is emitted.
*/
if (option === Region.SelfHosted) {
this.onOpenSelfHostedSettings.emit();
if (await this.configService.getFeatureFlag(FeatureFlag.UnauthenticatedExtensionUIRefresh)) {
if (await SelfHostedEnvConfigDialogComponent.open(this.dialogService)) {
this.toastService.showToast({
variant: "success",
title: null,
message: this.i18nService.t("environmentSaved"),
});
}
} else {
this.onOpenSelfHostedSettings.emit();
}
return;
}

View File

@@ -55,3 +55,6 @@ export * from "./lock/lock-component.service";
// vault timeout
export * from "./vault-timeout-input/vault-timeout-input.component";
// self hosted environment configuration dialog
export * from "./self-hosted-env-config-dialog/self-hosted-env-config-dialog.component";

View File

@@ -15,7 +15,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService, FormFieldModule, SelectModule, ToastService } from "@bitwarden/components";
import { RegistrationSelfHostedEnvConfigDialogComponent } from "./registration-self-hosted-env-config-dialog.component";
import { SelfHostedEnvConfigDialogComponent } from "../../self-hosted-env-config-dialog/self-hosted-env-config-dialog.component";
/**
* Component for selecting the environment to register with in the email verification registration flow.
@@ -125,9 +125,7 @@ export class RegistrationEnvSelectorComponent implements OnInit, OnDestroy {
}
if (selectedRegion === Region.SelfHosted) {
return from(
RegistrationSelfHostedEnvConfigDialogComponent.open(this.dialogService),
).pipe(
return from(SelfHostedEnvConfigDialogComponent.open(this.dialogService)).pipe(
tap((result: boolean | undefined) =>
this.handleSelfHostedEnvConfigDialogResult(result, prevSelectedRegion),
),

View File

@@ -10,7 +10,7 @@ import {
ValidationErrors,
ValidatorFn,
} from "@angular/forms";
import { Subject, firstValueFrom } from "rxjs";
import { Subject, firstValueFrom, take, filter, takeUntil } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import {
@@ -54,8 +54,8 @@ function selfHostedEnvSettingsFormValidator(): ValidatorFn {
*/
@Component({
standalone: true,
selector: "auth-registration-self-hosted-env-config-dialog",
templateUrl: "registration-self-hosted-env-config-dialog.component.html",
selector: "self-hosted-env-config-dialog",
templateUrl: "self-hosted-env-config-dialog.component.html",
imports: [
CommonModule,
JslibModule,
@@ -68,14 +68,14 @@ function selfHostedEnvSettingsFormValidator(): ValidatorFn {
AsyncActionsModule,
],
})
export class RegistrationSelfHostedEnvConfigDialogComponent implements OnInit, OnDestroy {
export class SelfHostedEnvConfigDialogComponent implements OnInit, OnDestroy {
/**
* Opens the dialog.
* @param dialogService - Dialog service.
* @returns Promise that resolves to true if the dialog was closed with a successful result, false otherwise.
*/
static async open(dialogService: DialogService): Promise<boolean> {
const dialogRef = dialogService.open<boolean>(RegistrationSelfHostedEnvConfigDialogComponent, {
const dialogRef = dialogService.open<boolean>(SelfHostedEnvConfigDialogComponent, {
disableClose: false,
});
@@ -131,7 +131,33 @@ export class RegistrationSelfHostedEnvConfigDialogComponent implements OnInit, O
private environmentService: EnvironmentService,
) {}
ngOnInit() {}
ngOnInit() {
/**
* Populate the form with the current self-hosted environment settings.
*/
this.environmentService.environment$
.pipe(
take(1),
filter((env) => {
const region = env.getRegion();
return region === Region.SelfHosted;
}),
takeUntil(this.destroy$),
)
.subscribe({
next: (env) => {
const urls = env.getUrls();
this.formGroup.patchValue({
baseUrl: urls.base || "",
webVaultUrl: urls.webVault || "",
apiUrl: urls.api || "",
identityUrl: urls.identity || "",
iconsUrl: urls.icons || "",
notificationsUrl: urls.notifications || "",
});
},
});
}
submit = async () => {
this.showErrorSummary = false;

View File

@@ -45,6 +45,24 @@ const LOGGED_OUT_INFO: AccountInfo = {
name: undefined,
};
/**
* An rxjs map operator that extracts the UserId from an account, or throws if the account or UserId are null.
*/
export const getUserId = map<{ id: UserId | undefined }, UserId>((account) => {
if (account?.id == null) {
throw new Error("Null account or account ID");
}
return account.id;
});
/**
* An rxjs map operator that extracts the UserId from an account, or returns undefined if the account or UserId are null.
*/
export const getOptionalUserId = map<{ id: UserId | undefined }, UserId | undefined>(
(account) => account?.id ?? undefined,
);
export class AccountServiceImplementation implements InternalAccountService {
private accountsState: GlobalState<Record<UserId, AccountInfo>>;
private activeAccountIdState: GlobalState<UserId | undefined>;

2
package-lock.json generated
View File

@@ -234,7 +234,7 @@
},
"apps/desktop": {
"name": "@bitwarden/desktop",
"version": "2024.10.2",
"version": "2024.10.3",
"hasInstallScript": true,
"license": "GPL-3.0"
},