1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-30 16:23:53 +00:00

Merge branch 'main' into PM-23851-False-Requirement-to-Pop-Out-Extension-When-Using-Send-Files

This commit is contained in:
John Harrington
2026-01-13 15:49:26 -07:00
committed by GitHub
9 changed files with 148 additions and 65 deletions

View File

@@ -1,5 +1,3 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, EventEmitter, Input, Output, ChangeDetectionStrategy } from "@angular/core";
@@ -33,13 +31,10 @@ export class Fido2CipherRowComponent {
@Output() onSelected = new EventEmitter<CipherView>();
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() cipher: CipherView;
@Input({ required: true }) cipher!: CipherView;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() last: boolean;
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@Input() title: string;
@Input({ required: true }) title!: string;
protected selectCipher(c: CipherView) {
this.onSelected.emit(c);

View File

@@ -1,17 +1,17 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, ChangeDetectionStrategy } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ReactiveFormsModule } from "@angular/forms";
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { BreachAccountResponse } from "@bitwarden/common/dirt/models/response/breach-account.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { mockAccountInfoWith } from "@bitwarden/common/spec";
import { UserId } from "@bitwarden/common/types/guid";
import { AsyncActionsModule, ButtonModule, FormFieldModule } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { BreachReportComponent } from "./breach-report.component";
@@ -32,6 +32,21 @@ const breachedAccounts = [
}),
];
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-header",
template: "<div></div>",
standalone: false,
})
class MockHeaderComponent {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "bit-container",
template: "<div></div>",
standalone: false,
})
class MockBitContainerComponent {}
describe("BreachReportComponent", () => {
let component: BreachReportComponent;
let fixture: ComponentFixture<BreachReportComponent>;
@@ -51,8 +66,8 @@ describe("BreachReportComponent", () => {
accountService.activeAccount$ = activeAccountSubject;
await TestBed.configureTestingModule({
declarations: [BreachReportComponent, I18nPipe],
imports: [ReactiveFormsModule],
declarations: [BreachReportComponent, MockHeaderComponent, MockBitContainerComponent],
imports: [ReactiveFormsModule, I18nPipe, AsyncActionsModule, ButtonModule, FormFieldModule],
providers: [
{
provide: AuditService,
@@ -67,9 +82,7 @@ describe("BreachReportComponent", () => {
useValue: mock<I18nService>(),
},
],
// FIXME(PM-18598): Replace unknownElements and unknownProperties with actual imports
errorOnUnknownElements: false,
errorOnUnknownProperties: false,
schemas: [],
}).compileComponents();
});

View File

@@ -1,8 +1,8 @@
import { Component, ChangeDetectionStrategy } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@@ -12,7 +12,13 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp
import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import {
DialogService,
AsyncActionsModule,
ButtonModule,
FormFieldModule,
} from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { CipherFormConfigService, PasswordRepromptService } from "@bitwarden/vault";
import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/services/admin-console-cipher-form-config.service";
@@ -20,6 +26,22 @@ import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/se
import { ExposedPasswordsReportComponent } from "./exposed-passwords-report.component";
import { cipherData } from "./reports-ciphers.mock";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-header",
template: "<div></div>",
standalone: false,
})
class MockHeaderComponent {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "bit-container",
template: "<div></div>",
standalone: false,
})
class MockBitContainerComponent {}
describe("ExposedPasswordsReportComponent", () => {
let component: ExposedPasswordsReportComponent;
let fixture: ComponentFixture<ExposedPasswordsReportComponent>;
@@ -30,16 +52,19 @@ describe("ExposedPasswordsReportComponent", () => {
const userId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(userId);
beforeEach(() => {
beforeEach(async () => {
let cipherFormConfigServiceMock: MockProxy<CipherFormConfigService>;
syncServiceMock = mock<SyncService>();
auditService = mock<AuditService>();
organizationService = mock<OrganizationService>();
organizationService.organizations$.mockReturnValue(of([]));
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
TestBed.configureTestingModule({
declarations: [ExposedPasswordsReportComponent, I18nPipe],
await TestBed.configureTestingModule({
declarations: [
ExposedPasswordsReportComponent,
MockHeaderComponent,
MockBitContainerComponent,
],
imports: [I18nPipe, AsyncActionsModule, ButtonModule, FormFieldModule],
providers: [
{
provide: CipherService,
@@ -83,9 +108,6 @@ describe("ExposedPasswordsReportComponent", () => {
},
],
schemas: [],
// FIXME(PM-18598): Replace unknownElements and unknownProperties with actual imports
errorOnUnknownElements: false,
errorOnUnknownProperties: false,
}).compileComponents();
});

View File

@@ -3,7 +3,6 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
import { MockProxy, mock } from "jest-mock-extended";
import { of } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -14,6 +13,7 @@ import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { CipherFormConfigService, PasswordRepromptService } from "@bitwarden/vault";
import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/services/admin-console-cipher-form-config.service";
@@ -37,7 +37,8 @@ describe("InactiveTwoFactorReportComponent", () => {
syncServiceMock = mock<SyncService>();
await TestBed.configureTestingModule({
declarations: [InactiveTwoFactorReportComponent, I18nPipe],
declarations: [InactiveTwoFactorReportComponent],
imports: [I18nPipe],
providers: [
{
provide: CipherService,

View File

@@ -1,8 +1,8 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { MockProxy, mock } from "jest-mock-extended";
import { of } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -12,6 +12,7 @@ import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { CipherFormConfigService, PasswordRepromptService } from "@bitwarden/vault";
import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/services/admin-console-cipher-form-config.service";
@@ -19,6 +20,22 @@ import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/se
import { cipherData } from "./reports-ciphers.mock";
import { ReusedPasswordsReportComponent } from "./reused-passwords-report.component";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-header",
template: "<div></div>",
standalone: false,
})
class MockHeaderComponent {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "bit-container",
template: "<div></div>",
standalone: false,
})
class MockBitContainerComponent {}
describe("ReusedPasswordsReportComponent", () => {
let component: ReusedPasswordsReportComponent;
let fixture: ComponentFixture<ReusedPasswordsReportComponent>;
@@ -28,15 +45,18 @@ describe("ReusedPasswordsReportComponent", () => {
const userId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(userId);
beforeEach(() => {
beforeEach(async () => {
let cipherFormConfigServiceMock: MockProxy<CipherFormConfigService>;
organizationService = mock<OrganizationService>();
organizationService.organizations$.mockReturnValue(of([]));
syncServiceMock = mock<SyncService>();
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
TestBed.configureTestingModule({
declarations: [ReusedPasswordsReportComponent, I18nPipe],
await TestBed.configureTestingModule({
declarations: [
ReusedPasswordsReportComponent,
MockHeaderComponent,
MockBitContainerComponent,
],
imports: [I18nPipe],
providers: [
{
provide: CipherService,
@@ -76,8 +96,6 @@ describe("ReusedPasswordsReportComponent", () => {
},
],
schemas: [],
// FIXME(PM-18598): Replace unknownElements and unknownProperties with actual imports
errorOnUnknownElements: false,
}).compileComponents();
});

View File

@@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { MockProxy, mock } from "jest-mock-extended";
import { of } from "rxjs";
import { CollectionService } from "@bitwarden/admin-console/common";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -13,6 +13,7 @@ import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { CipherFormConfigService, PasswordRepromptService } from "@bitwarden/vault";
import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/services/admin-console-cipher-form-config.service";
@@ -20,6 +21,22 @@ import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/se
import { cipherData } from "./reports-ciphers.mock";
import { UnsecuredWebsitesReportComponent } from "./unsecured-websites-report.component";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-header",
template: "<div></div>",
standalone: false,
})
class MockHeaderComponent {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "bit-container",
template: "<div></div>",
standalone: false,
})
class MockBitContainerComponent {}
describe("UnsecuredWebsitesReportComponent", () => {
let component: UnsecuredWebsitesReportComponent;
let fixture: ComponentFixture<UnsecuredWebsitesReportComponent>;
@@ -30,7 +47,7 @@ describe("UnsecuredWebsitesReportComponent", () => {
const userId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(userId);
beforeEach(() => {
beforeEach(async () => {
let cipherFormConfigServiceMock: MockProxy<CipherFormConfigService>;
organizationService = mock<OrganizationService>();
organizationService.organizations$.mockReturnValue(of([]));
@@ -38,10 +55,13 @@ describe("UnsecuredWebsitesReportComponent", () => {
collectionService = mock<CollectionService>();
adminConsoleCipherFormConfigService = mock<AdminConsoleCipherFormConfigService>();
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
TestBed.configureTestingModule({
declarations: [UnsecuredWebsitesReportComponent, I18nPipe],
await TestBed.configureTestingModule({
declarations: [
UnsecuredWebsitesReportComponent,
MockHeaderComponent,
MockBitContainerComponent,
],
imports: [I18nPipe],
providers: [
{
provide: CipherService,
@@ -85,8 +105,6 @@ describe("UnsecuredWebsitesReportComponent", () => {
},
],
schemas: [],
// FIXME(PM-18598): Replace unknownElements and unknownProperties with actual imports
errorOnUnknownElements: false,
}).compileComponents();
});

View File

@@ -1,8 +1,8 @@
import { ChangeDetectionStrategy, Component } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { mock, MockProxy } from "jest-mock-extended";
import { of } from "rxjs";
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -13,6 +13,7 @@ import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService } from "@bitwarden/components";
import { I18nPipe } from "@bitwarden/ui-common";
import { CipherFormConfigService, PasswordRepromptService } from "@bitwarden/vault";
import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/services/admin-console-cipher-form-config.service";
@@ -20,6 +21,22 @@ import { AdminConsoleCipherFormConfigService } from "../../../vault/org-vault/se
import { cipherData } from "./reports-ciphers.mock";
import { WeakPasswordsReportComponent } from "./weak-passwords-report.component";
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "app-header",
template: "<div></div>",
standalone: false,
})
class MockHeaderComponent {}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: "bit-container",
template: "<div></div>",
standalone: false,
})
class MockBitContainerComponent {}
describe("WeakPasswordsReportComponent", () => {
let component: WeakPasswordsReportComponent;
let fixture: ComponentFixture<WeakPasswordsReportComponent>;
@@ -30,16 +47,16 @@ describe("WeakPasswordsReportComponent", () => {
const userId = Utils.newGuid() as UserId;
const accountService: FakeAccountService = mockAccountServiceWith(userId);
beforeEach(() => {
beforeEach(async () => {
let cipherFormConfigServiceMock: MockProxy<CipherFormConfigService>;
syncServiceMock = mock<SyncService>();
passwordStrengthService = mock<PasswordStrengthServiceAbstraction>();
organizationService = mock<OrganizationService>();
organizationService.organizations$.mockReturnValue(of([]));
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises
TestBed.configureTestingModule({
declarations: [WeakPasswordsReportComponent, I18nPipe],
await TestBed.configureTestingModule({
declarations: [WeakPasswordsReportComponent, MockHeaderComponent, MockBitContainerComponent],
imports: [I18nPipe],
providers: [
{
provide: CipherService,
@@ -84,8 +101,6 @@ describe("WeakPasswordsReportComponent", () => {
},
],
schemas: [],
// FIXME(PM-18598): Replace unknownElements and unknownProperties with actual imports
errorOnUnknownElements: false,
}).compileComponents();
});

View File

@@ -106,15 +106,17 @@
></button>
}
}
<button
bitIconButton="bwi-trash"
type="button"
buttonType="danger"
[label]="'delete' | i18n"
[bitAction]="delete"
[disabled]="!canDelete"
data-testid="delete-cipher-btn"
></button>
@if (cipher) {
<button
bitIconButton="bwi-trash"
type="button"
buttonType="danger"
[label]="'delete' | i18n"
[bitAction]="delete"
[disabled]="!canDelete"
data-testid="delete-cipher-btn"
></button>
}
</div>
}
</ng-container>

View File

@@ -30,7 +30,6 @@ import {
Fido2ClientService as Fido2ClientServiceAbstraction,
PublicKeyCredentialParam,
UserRequestedFallbackAbortReason,
UserVerification,
} from "../../abstractions/fido2/fido2-client.service.abstraction";
import { LogService } from "../../abstractions/log.service";
import { Utils } from "../../misc/utils";
@@ -195,7 +194,7 @@ export class Fido2ClientService<
}
const timeoutSubscription = this.setAbortTimeout(
abortController,
params.authenticatorSelection?.userVerification,
makeCredentialParams.requireUserVerification,
params.timeout,
);
@@ -318,7 +317,7 @@ export class Fido2ClientService<
const timeoutSubscription = this.setAbortTimeout(
abortController,
params.userVerification,
getAssertionParams.requireUserVerification,
params.timeout,
);
@@ -441,13 +440,13 @@ export class Fido2ClientService<
private setAbortTimeout = (
abortController: AbortController,
userVerification?: UserVerification,
requireUserVerification: boolean,
timeout?: number,
): Subscription => {
let clampedTimeout: number;
const { WITH_VERIFICATION, NO_VERIFICATION } = this.TIMEOUTS;
if (userVerification === "required") {
if (requireUserVerification) {
timeout = timeout ?? WITH_VERIFICATION.DEFAULT;
clampedTimeout = Math.max(WITH_VERIFICATION.MIN, Math.min(timeout, WITH_VERIFICATION.MAX));
} else {