mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 06:13:38 +00:00
Remove debugging tabs (#15510)
This commit is contained in:
@@ -1,51 +0,0 @@
|
|||||||
<bit-container>
|
|
||||||
<p>{{ "passwordsReportDesc" | i18n }}</p>
|
|
||||||
<div *ngIf="loading">
|
|
||||||
<i
|
|
||||||
class="bwi bwi-spinner bwi-spin tw-text-muted"
|
|
||||||
title="{{ 'loading' | i18n }}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="tw-mt-4" *ngIf="!loading">
|
|
||||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="53">
|
|
||||||
<ng-container header>
|
|
||||||
<th bitCell bitSortable="hostURI">{{ "application" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "weakness" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesExposed" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "totalMembers" | i18n }}</th>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template bitRowDef let-row>
|
|
||||||
<td bitCell>
|
|
||||||
<ng-container>
|
|
||||||
<span>{{ row.hostURI }}</span>
|
|
||||||
</ng-container>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span
|
|
||||||
bitBadge
|
|
||||||
*ngIf="passwordStrengthMap.has(row.id)"
|
|
||||||
[variant]="passwordStrengthMap.get(row.id)[1]"
|
|
||||||
>
|
|
||||||
{{ passwordStrengthMap.get(row.id)[0] | i18n }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge *ngIf="passwordUseMap.has(row.login.password)" variant="warning">
|
|
||||||
{{ "reusedXTimes" | i18n: passwordUseMap.get(row.login.password) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge *ngIf="exposedPasswordMap.has(row.id)" variant="warning">
|
|
||||||
{{ "exposedXTimes" | i18n: exposedPasswordMap.get(row.id) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right" data-testid="total-membership">
|
|
||||||
{{ totalMembersMap.get(row.id) || 0 }}
|
|
||||||
</td>
|
|
||||||
</ng-template>
|
|
||||||
</bit-table-scroll>
|
|
||||||
</div>
|
|
||||||
</bit-container>
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
|
||||||
import { ActivatedRoute, convertToParamMap } from "@angular/router";
|
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
|
||||||
import { of } from "rxjs";
|
|
||||||
|
|
||||||
import {
|
|
||||||
MemberCipherDetailsApiService,
|
|
||||||
PasswordHealthService,
|
|
||||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights";
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
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";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|
||||||
import { mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
|
||||||
import { TableModule } from "@bitwarden/components";
|
|
||||||
import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared";
|
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
|
||||||
|
|
||||||
import { PasswordHealthMembersURIComponent } from "./password-health-members-uri.component";
|
|
||||||
|
|
||||||
describe("PasswordHealthMembersUriComponent", () => {
|
|
||||||
let component: PasswordHealthMembersURIComponent;
|
|
||||||
let fixture: ComponentFixture<PasswordHealthMembersURIComponent>;
|
|
||||||
let cipherServiceMock: MockProxy<CipherService>;
|
|
||||||
const passwordHealthServiceMock = mock<PasswordHealthService>();
|
|
||||||
const userId = Utils.newGuid() as UserId;
|
|
||||||
|
|
||||||
const activeRouteParams = convertToParamMap({ organizationId: "orgId" });
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
cipherServiceMock = mock<CipherService>();
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [PasswordHealthMembersURIComponent, PipesModule, TableModule, LooseComponentsModule],
|
|
||||||
providers: [
|
|
||||||
{ provide: CipherService, useValue: cipherServiceMock },
|
|
||||||
{ provide: I18nService, useValue: mock<I18nService>() },
|
|
||||||
{ provide: AuditService, useValue: mock<AuditService>() },
|
|
||||||
{ provide: OrganizationService, useValue: mock<OrganizationService>() },
|
|
||||||
{ provide: AccountService, useValue: mockAccountServiceWith(userId) },
|
|
||||||
{
|
|
||||||
provide: PasswordStrengthServiceAbstraction,
|
|
||||||
useValue: mock<PasswordStrengthServiceAbstraction>(),
|
|
||||||
},
|
|
||||||
{ provide: PasswordHealthService, useValue: passwordHealthServiceMock },
|
|
||||||
{
|
|
||||||
provide: ActivatedRoute,
|
|
||||||
useValue: {
|
|
||||||
paramMap: of(activeRouteParams),
|
|
||||||
url: of([]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: MemberCipherDetailsApiService,
|
|
||||||
useValue: mock<MemberCipherDetailsApiService>(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: ApiService,
|
|
||||||
useValue: mock<ApiService>(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(PasswordHealthMembersURIComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should initialize component", () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { CommonModule } from "@angular/common";
|
|
||||||
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
|
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import { map } from "rxjs";
|
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|
||||||
import {
|
|
||||||
MemberCipherDetailsApiService,
|
|
||||||
PasswordHealthService,
|
|
||||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights";
|
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|
||||||
import {
|
|
||||||
BadgeModule,
|
|
||||||
BadgeVariant,
|
|
||||||
ContainerComponent,
|
|
||||||
TableDataSource,
|
|
||||||
TableModule,
|
|
||||||
} from "@bitwarden/components";
|
|
||||||
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "tools-password-health-members-uri",
|
|
||||||
templateUrl: "password-health-members-uri.component.html",
|
|
||||||
imports: [
|
|
||||||
BadgeModule,
|
|
||||||
CommonModule,
|
|
||||||
ContainerComponent,
|
|
||||||
PipesModule,
|
|
||||||
JslibModule,
|
|
||||||
HeaderModule,
|
|
||||||
TableModule,
|
|
||||||
],
|
|
||||||
providers: [PasswordHealthService, MemberCipherDetailsApiService],
|
|
||||||
})
|
|
||||||
export class PasswordHealthMembersURIComponent implements OnInit {
|
|
||||||
passwordStrengthMap = new Map<string, [string, BadgeVariant]>();
|
|
||||||
|
|
||||||
weakPasswordCiphers: CipherView[] = [];
|
|
||||||
|
|
||||||
passwordUseMap = new Map<string, number>();
|
|
||||||
|
|
||||||
exposedPasswordMap = new Map<string, number>();
|
|
||||||
|
|
||||||
totalMembersMap = new Map<string, number>();
|
|
||||||
|
|
||||||
dataSource = new TableDataSource<CipherView>();
|
|
||||||
|
|
||||||
reportCiphers: (CipherView & { hostURI: string })[] = [];
|
|
||||||
reportCipherURIs: string[] = [];
|
|
||||||
|
|
||||||
organization: Organization;
|
|
||||||
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
private destroyRef = inject(DestroyRef);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected cipherService: CipherService,
|
|
||||||
protected passwordStrengthService: PasswordStrengthServiceAbstraction,
|
|
||||||
protected organizationService: OrganizationService,
|
|
||||||
protected auditService: AuditService,
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected activatedRoute: ActivatedRoute,
|
|
||||||
protected memberCipherDetailsApiService: MemberCipherDetailsApiService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.activatedRoute.paramMap
|
|
||||||
.pipe(
|
|
||||||
takeUntilDestroyed(this.destroyRef),
|
|
||||||
map(async (params) => {
|
|
||||||
const organizationId = params.get("organizationId");
|
|
||||||
await this.setCiphers(organizationId);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setCiphers(organizationId: string) {
|
|
||||||
const passwordHealthService = new PasswordHealthService(
|
|
||||||
this.passwordStrengthService,
|
|
||||||
this.auditService,
|
|
||||||
this.cipherService,
|
|
||||||
this.memberCipherDetailsApiService,
|
|
||||||
organizationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
await passwordHealthService.generateReport();
|
|
||||||
|
|
||||||
this.dataSource.data = passwordHealthService.groupCiphersByLoginUri();
|
|
||||||
this.exposedPasswordMap = passwordHealthService.exposedPasswordMap;
|
|
||||||
this.passwordStrengthMap = passwordHealthService.passwordStrengthMap;
|
|
||||||
this.passwordUseMap = passwordHealthService.passwordUseMap;
|
|
||||||
this.totalMembersMap = passwordHealthService.totalMembersMap;
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<p>{{ "passwordsReportDesc" | i18n }}</p>
|
|
||||||
<div *ngIf="loading">
|
|
||||||
<i
|
|
||||||
class="bwi bwi-spinner bwi-spin tw-text-muted"
|
|
||||||
title="{{ 'loading' | i18n }}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="tw-flex tw-flex-col" *ngIf="!loading && dataSource.data.length">
|
|
||||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="74">
|
|
||||||
<ng-container header>
|
|
||||||
<th bitCell></th>
|
|
||||||
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "weakness" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesExposed" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "totalMembers" | i18n }}</th>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template bitRowDef let-row>
|
|
||||||
<td bitCell>
|
|
||||||
<input
|
|
||||||
bitCheckbox
|
|
||||||
type="checkbox"
|
|
||||||
[checked]="selectedIds.has(row.id)"
|
|
||||||
(change)="onCheckboxChange(row.id, $event)"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td bitCell>
|
|
||||||
<ng-container>
|
|
||||||
<span>{{ row.name }}</span>
|
|
||||||
</ng-container>
|
|
||||||
<br />
|
|
||||||
<small>{{ row.subTitle }}</small>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span
|
|
||||||
bitBadge
|
|
||||||
*ngIf="passwordStrengthMap.has(row.id)"
|
|
||||||
[variant]="passwordStrengthMap.get(row.id)[1]"
|
|
||||||
>
|
|
||||||
{{ passwordStrengthMap.get(row.id)[0] | i18n }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge *ngIf="passwordUseMap.has(row.login.password)" variant="warning">
|
|
||||||
{{ "reusedXTimes" | i18n: passwordUseMap.get(row.login.password) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge *ngIf="exposedPasswordMap.has(row.id)" variant="warning">
|
|
||||||
{{ "exposedXTimes" | i18n: exposedPasswordMap.get(row.id) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right" data-testid="total-membership">
|
|
||||||
{{ totalMembersMap.get(row.id) || 0 }}
|
|
||||||
</td>
|
|
||||||
</ng-template>
|
|
||||||
</bit-table-scroll>
|
|
||||||
</div>
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
|
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
||||||
import { FormControl, FormsModule } from "@angular/forms";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import { debounceTime, map } from "rxjs";
|
|
||||||
|
|
||||||
import {
|
|
||||||
MemberCipherDetailsApiService,
|
|
||||||
PasswordHealthService,
|
|
||||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights";
|
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|
||||||
import {
|
|
||||||
BadgeVariant,
|
|
||||||
SearchModule,
|
|
||||||
TableDataSource,
|
|
||||||
TableModule,
|
|
||||||
ToastService,
|
|
||||||
} from "@bitwarden/components";
|
|
||||||
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
|
||||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "tools-password-health-members",
|
|
||||||
templateUrl: "password-health-members.component.html",
|
|
||||||
imports: [PipesModule, HeaderModule, SearchModule, FormsModule, SharedModule, TableModule],
|
|
||||||
providers: [PasswordHealthService, MemberCipherDetailsApiService],
|
|
||||||
})
|
|
||||||
export class PasswordHealthMembersComponent implements OnInit {
|
|
||||||
passwordStrengthMap = new Map<string, [string, BadgeVariant]>();
|
|
||||||
|
|
||||||
passwordUseMap = new Map<string, number>();
|
|
||||||
|
|
||||||
exposedPasswordMap = new Map<string, number>();
|
|
||||||
|
|
||||||
totalMembersMap = new Map<string, number>();
|
|
||||||
|
|
||||||
dataSource = new TableDataSource<CipherView>();
|
|
||||||
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
selectedIds: Set<number> = new Set<number>();
|
|
||||||
|
|
||||||
protected searchControl = new FormControl("", { nonNullable: true });
|
|
||||||
|
|
||||||
private destroyRef = inject(DestroyRef);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected cipherService: CipherService,
|
|
||||||
protected passwordStrengthService: PasswordStrengthServiceAbstraction,
|
|
||||||
protected auditService: AuditService,
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected activatedRoute: ActivatedRoute,
|
|
||||||
protected toastService: ToastService,
|
|
||||||
protected memberCipherDetailsApiService: MemberCipherDetailsApiService,
|
|
||||||
) {
|
|
||||||
this.searchControl.valueChanges
|
|
||||||
.pipe(debounceTime(200), takeUntilDestroyed())
|
|
||||||
.subscribe((v) => (this.dataSource.filter = v));
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.activatedRoute.paramMap
|
|
||||||
.pipe(
|
|
||||||
takeUntilDestroyed(this.destroyRef),
|
|
||||||
map(async (params) => {
|
|
||||||
const organizationId = params.get("organizationId");
|
|
||||||
await this.setCiphers(organizationId);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setCiphers(organizationId: string) {
|
|
||||||
const passwordHealthService = new PasswordHealthService(
|
|
||||||
this.passwordStrengthService,
|
|
||||||
this.auditService,
|
|
||||||
this.cipherService,
|
|
||||||
this.memberCipherDetailsApiService,
|
|
||||||
organizationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
await passwordHealthService.generateReport();
|
|
||||||
|
|
||||||
this.dataSource.data = passwordHealthService.reportCiphers;
|
|
||||||
|
|
||||||
this.exposedPasswordMap = passwordHealthService.exposedPasswordMap;
|
|
||||||
this.passwordStrengthMap = passwordHealthService.passwordStrengthMap;
|
|
||||||
this.passwordUseMap = passwordHealthService.passwordUseMap;
|
|
||||||
this.totalMembersMap = passwordHealthService.totalMembersMap;
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
markAppsAsCritical = async () => {
|
|
||||||
// TODO: Send to API once implemented
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.selectedIds.clear();
|
|
||||||
this.toastService.showToast({
|
|
||||||
variant: "success",
|
|
||||||
title: null,
|
|
||||||
message: this.i18nService.t("appsMarkedAsCritical"),
|
|
||||||
});
|
|
||||||
resolve(true);
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
trackByFunction(_: number, item: CipherView) {
|
|
||||||
return item.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
onCheckboxChange(id: number, event: Event) {
|
|
||||||
const isChecked = (event.target as HTMLInputElement).checked;
|
|
||||||
if (isChecked) {
|
|
||||||
this.selectedIds.add(id);
|
|
||||||
} else {
|
|
||||||
this.selectedIds.delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<bit-container>
|
|
||||||
<p>{{ "passwordsReportDesc" | i18n }}</p>
|
|
||||||
<div *ngIf="loading">
|
|
||||||
<i
|
|
||||||
class="bwi bwi-spinner bwi-spin tw-text-muted"
|
|
||||||
title="{{ 'loading' | i18n }}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></i>
|
|
||||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="tw-mt-4" *ngIf="!loading && dataSource.data.length">
|
|
||||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="53">
|
|
||||||
<ng-container header>
|
|
||||||
<th bitCell></th>
|
|
||||||
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "weakness" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
|
|
||||||
<th bitCell class="tw-text-right">{{ "timesExposed" | i18n }}</th>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template bitRowDef let-row>
|
|
||||||
<td bitCell>
|
|
||||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
|
||||||
</td>
|
|
||||||
<td bitCell>
|
|
||||||
<ng-container>
|
|
||||||
<span>{{ row.name }}</span>
|
|
||||||
</ng-container>
|
|
||||||
<br />
|
|
||||||
<small>{{ row.subTitle }}</small>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span
|
|
||||||
bitBadge
|
|
||||||
*ngIf="row.weakPasswordDetail"
|
|
||||||
[variant]="row.weakPasswordDetail?.detailValue.badgeVariant"
|
|
||||||
>
|
|
||||||
{{ row.weakPasswordDetail?.detailValue.label | i18n }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge *ngIf="passwordUseMap.has(row.login.password)" variant="warning">
|
|
||||||
{{ "reusedXTimes" | i18n: passwordUseMap.get(row.login.password) }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-text-right">
|
|
||||||
<span bitBadge variant="warning" *ngIf="row.exposedPasswordDetail">
|
|
||||||
{{ "exposedXTimes" | i18n: row.exposedPasswordDetail?.exposedXTimes }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</ng-template>
|
|
||||||
</bit-table-scroll>
|
|
||||||
</div>
|
|
||||||
</bit-container>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
|
||||||
import { ActivatedRoute, convertToParamMap } from "@angular/router";
|
|
||||||
import { mock } from "jest-mock-extended";
|
|
||||||
import { of } from "rxjs";
|
|
||||||
|
|
||||||
import { RiskInsightsReportService } from "@bitwarden/bit-common/dirt/reports/risk-insights";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { TableModule } from "@bitwarden/components";
|
|
||||||
import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared";
|
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
|
||||||
|
|
||||||
import { PasswordHealthComponent } from "./password-health.component";
|
|
||||||
|
|
||||||
describe("PasswordHealthComponent", () => {
|
|
||||||
let component: PasswordHealthComponent;
|
|
||||||
let fixture: ComponentFixture<PasswordHealthComponent>;
|
|
||||||
const activeRouteParams = convertToParamMap({ organizationId: "orgId" });
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [PasswordHealthComponent, PipesModule, TableModule, LooseComponentsModule],
|
|
||||||
declarations: [],
|
|
||||||
providers: [
|
|
||||||
{ provide: RiskInsightsReportService, useValue: mock<RiskInsightsReportService>() },
|
|
||||||
{ provide: I18nService, useValue: mock<I18nService>() },
|
|
||||||
{
|
|
||||||
provide: ActivatedRoute,
|
|
||||||
useValue: {
|
|
||||||
paramMap: of(activeRouteParams),
|
|
||||||
url: of([]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compileComponents();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(PasswordHealthComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should initialize component", () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call generateReport on init", () => {});
|
|
||||||
});
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { CommonModule } from "@angular/common";
|
|
||||||
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
|
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import { firstValueFrom, map } from "rxjs";
|
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|
||||||
import { RiskInsightsReportService } from "@bitwarden/bit-common/dirt/reports/risk-insights";
|
|
||||||
import { CipherHealthReportDetail } from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import {
|
|
||||||
BadgeModule,
|
|
||||||
ContainerComponent,
|
|
||||||
TableDataSource,
|
|
||||||
TableModule,
|
|
||||||
} from "@bitwarden/components";
|
|
||||||
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
|
||||||
import { OrganizationBadgeModule } from "@bitwarden/web-vault/app/vault/individual-vault/organization-badge/organization-badge.module";
|
|
||||||
import { PipesModule } from "@bitwarden/web-vault/app/vault/individual-vault/pipes/pipes.module";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "tools-password-health",
|
|
||||||
templateUrl: "password-health.component.html",
|
|
||||||
imports: [
|
|
||||||
BadgeModule,
|
|
||||||
OrganizationBadgeModule,
|
|
||||||
CommonModule,
|
|
||||||
ContainerComponent,
|
|
||||||
PipesModule,
|
|
||||||
JslibModule,
|
|
||||||
HeaderModule,
|
|
||||||
TableModule,
|
|
||||||
],
|
|
||||||
})
|
|
||||||
export class PasswordHealthComponent implements OnInit {
|
|
||||||
passwordUseMap = new Map<string, number>();
|
|
||||||
dataSource = new TableDataSource<CipherHealthReportDetail>();
|
|
||||||
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
private destroyRef = inject(DestroyRef);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected riskInsightsReportService: RiskInsightsReportService,
|
|
||||||
protected i18nService: I18nService,
|
|
||||||
protected activatedRoute: ActivatedRoute,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.activatedRoute.paramMap
|
|
||||||
.pipe(
|
|
||||||
takeUntilDestroyed(this.destroyRef),
|
|
||||||
map(async (params) => {
|
|
||||||
const organizationId = params.get("organizationId");
|
|
||||||
await this.setCiphers(organizationId);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
async setCiphers(organizationId: string) {
|
|
||||||
this.dataSource.data = await firstValueFrom(
|
|
||||||
this.riskInsightsReportService.generateRawDataReport$(organizationId),
|
|
||||||
);
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,15 +45,6 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
<tools-critical-applications></tools-critical-applications>
|
<tools-critical-applications></tools-critical-applications>
|
||||||
</bit-tab>
|
</bit-tab>
|
||||||
<bit-tab *ngIf="showDebugTabs" label="Raw Data">
|
|
||||||
<tools-password-health></tools-password-health>
|
|
||||||
</bit-tab>
|
|
||||||
<bit-tab *ngIf="showDebugTabs" label="Raw Data + members">
|
|
||||||
<tools-password-health-members></tools-password-health-members>
|
|
||||||
</bit-tab>
|
|
||||||
<bit-tab *ngIf="showDebugTabs" label="Raw Data + uri">
|
|
||||||
<tools-password-health-members-uri></tools-password-health-members-uri>
|
|
||||||
</bit-tab>
|
|
||||||
</bit-tab-group>
|
</bit-tab-group>
|
||||||
|
|
||||||
<bit-drawer
|
<bit-drawer
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
PasswordHealthReportApplicationsResponse,
|
PasswordHealthReportApplicationsResponse,
|
||||||
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
|
} from "@bitwarden/bit-common/dirt/reports/risk-insights/models/password-health";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags";
|
|
||||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||||
import {
|
import {
|
||||||
AsyncActionsModule,
|
AsyncActionsModule,
|
||||||
@@ -31,9 +30,6 @@ import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.mod
|
|||||||
|
|
||||||
import { AllApplicationsComponent } from "./all-applications.component";
|
import { AllApplicationsComponent } from "./all-applications.component";
|
||||||
import { CriticalApplicationsComponent } from "./critical-applications.component";
|
import { CriticalApplicationsComponent } from "./critical-applications.component";
|
||||||
import { PasswordHealthMembersURIComponent } from "./password-health-members-uri.component";
|
|
||||||
import { PasswordHealthMembersComponent } from "./password-health-members.component";
|
|
||||||
import { PasswordHealthComponent } from "./password-health.component";
|
|
||||||
|
|
||||||
// FIXME: update to use a const object instead of a typescript enum
|
// FIXME: update to use a const object instead of a typescript enum
|
||||||
// eslint-disable-next-line @bitwarden/platform/no-enums
|
// eslint-disable-next-line @bitwarden/platform/no-enums
|
||||||
@@ -53,9 +49,6 @@ export enum RiskInsightsTabType {
|
|||||||
CriticalApplicationsComponent,
|
CriticalApplicationsComponent,
|
||||||
JslibModule,
|
JslibModule,
|
||||||
HeaderModule,
|
HeaderModule,
|
||||||
PasswordHealthComponent,
|
|
||||||
PasswordHealthMembersComponent,
|
|
||||||
PasswordHealthMembersURIComponent,
|
|
||||||
TabsModule,
|
TabsModule,
|
||||||
DrawerComponent,
|
DrawerComponent,
|
||||||
DrawerBodyComponent,
|
DrawerBodyComponent,
|
||||||
@@ -69,7 +62,6 @@ export class RiskInsightsComponent implements OnInit {
|
|||||||
dataLastUpdated: Date = new Date();
|
dataLastUpdated: Date = new Date();
|
||||||
|
|
||||||
criticalApps$: Observable<PasswordHealthReportApplicationsResponse[]> = new Observable();
|
criticalApps$: Observable<PasswordHealthReportApplicationsResponse[]> = new Observable();
|
||||||
showDebugTabs: boolean = false;
|
|
||||||
|
|
||||||
appsCount: number = 0;
|
appsCount: number = 0;
|
||||||
criticalAppsCount: number = 0;
|
criticalAppsCount: number = 0;
|
||||||
@@ -97,8 +89,6 @@ export class RiskInsightsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.showDebugTabs = devFlagEnabled("showRiskInsightsDebug");
|
|
||||||
|
|
||||||
this.route.paramMap
|
this.route.paramMap
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntilDestroyed(this.destroyRef),
|
takeUntilDestroyed(this.destroyRef),
|
||||||
|
|||||||
Reference in New Issue
Block a user