mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-29 12:55:21 +01:00
parent
23b02a770a
commit
612442c1bb
19
src/app/components/premium-badge.component.ts
Normal file
19
src/app/components/premium-badge.component.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-premium-badge",
|
||||
template: `
|
||||
<button *appNotPremium bit-badge badgeType="success" (click)="premiumRequired()">
|
||||
{{ "premium" | i18n }}
|
||||
</button>
|
||||
`,
|
||||
})
|
||||
export class PremiumBadgeComponent {
|
||||
constructor(private messagingService: MessagingService) {}
|
||||
|
||||
premiumRequired() {
|
||||
this.messagingService.send("premiumRequired");
|
||||
}
|
||||
}
|
@ -24,6 +24,9 @@
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/tools">{{ "tools" | i18n }}</a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/reports">{{ "reports" | i18n }}</a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/settings">{{ "settings" | i18n }}</a>
|
||||
</li>
|
||||
|
@ -11,11 +11,11 @@ import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { Cipher } from "jslib-common/models/domain/cipher";
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../tools/exposed-passwords-report.component";
|
||||
import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../reports/exposed-passwords-report.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-exposed-passwords-report",
|
||||
templateUrl: "../../tools/exposed-passwords-report.component.html",
|
||||
templateUrl: "../../reports/exposed-passwords-report.component.html",
|
||||
})
|
||||
export class ExposedPasswordsReportComponent extends BaseExposedPasswordsReportComponent {
|
||||
manageableCiphers: Cipher[];
|
||||
|
@ -10,11 +10,11 @@ import { PasswordRepromptService } from "jslib-common/abstractions/passwordRepro
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../tools/inactive-two-factor-report.component";
|
||||
import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../reports/inactive-two-factor-report.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-inactive-two-factor-report",
|
||||
templateUrl: "../../tools/inactive-two-factor-report.component.html",
|
||||
templateUrl: "../../reports/inactive-two-factor-report.component.html",
|
||||
})
|
||||
export class InactiveTwoFactorReportComponent extends BaseInactiveTwoFactorReportComponent {
|
||||
constructor(
|
||||
|
@ -10,11 +10,11 @@ import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { Cipher } from "jslib-common/models/domain/cipher";
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../tools/reused-passwords-report.component";
|
||||
import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../reports/reused-passwords-report.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-reused-passwords-report",
|
||||
templateUrl: "../../tools/reused-passwords-report.component.html",
|
||||
templateUrl: "../../reports/reused-passwords-report.component.html",
|
||||
})
|
||||
export class ReusedPasswordsReportComponent extends BaseReusedPasswordsReportComponent {
|
||||
manageableCiphers: Cipher[];
|
||||
|
@ -9,11 +9,11 @@ import { PasswordRepromptService } from "jslib-common/abstractions/passwordRepro
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../tools/unsecured-websites-report.component";
|
||||
import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../reports/unsecured-websites-report.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-unsecured-websites-report",
|
||||
templateUrl: "../../tools/unsecured-websites-report.component.html",
|
||||
templateUrl: "../../reports/unsecured-websites-report.component.html",
|
||||
})
|
||||
export class UnsecuredWebsitesReportComponent extends BaseUnsecuredWebsitesReportComponent {
|
||||
constructor(
|
||||
|
@ -11,11 +11,11 @@ import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { Cipher } from "jslib-common/models/domain/cipher";
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../tools/weak-passwords-report.component";
|
||||
import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../reports/weak-passwords-report.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-weak-passwords-report",
|
||||
templateUrl: "../../tools/weak-passwords-report.component.html",
|
||||
templateUrl: "../../reports/weak-passwords-report.component.html",
|
||||
})
|
||||
export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportComponent {
|
||||
manageableCiphers: Cipher[];
|
||||
|
@ -64,16 +64,10 @@ import { SponsoredFamiliesComponent } from "./settings/sponsored-families.compon
|
||||
import { TwoFactorSetupComponent } from "./settings/two-factor-setup.component";
|
||||
import { UserBillingComponent } from "./settings/user-billing.component";
|
||||
import { UserSubscriptionComponent } from "./settings/user-subscription.component";
|
||||
import { BreachReportComponent } from "./tools/breach-report.component";
|
||||
import { ExportComponent } from "./tools/export.component";
|
||||
import { ExposedPasswordsReportComponent } from "./tools/exposed-passwords-report.component";
|
||||
import { ImportComponent } from "./tools/import.component";
|
||||
import { InactiveTwoFactorReportComponent } from "./tools/inactive-two-factor-report.component";
|
||||
import { PasswordGeneratorComponent } from "./tools/password-generator.component";
|
||||
import { ReusedPasswordsReportComponent } from "./tools/reused-passwords-report.component";
|
||||
import { ToolsComponent } from "./tools/tools.component";
|
||||
import { UnsecuredWebsitesReportComponent } from "./tools/unsecured-websites-report.component";
|
||||
import { WeakPasswordsReportComponent } from "./tools/weak-passwords-report.component";
|
||||
import { VaultComponent } from "./vault/vault.component";
|
||||
|
||||
const routes: Routes = [
|
||||
@ -242,38 +236,12 @@ const routes: Routes = [
|
||||
component: PasswordGeneratorComponent,
|
||||
data: { titleId: "generator" },
|
||||
},
|
||||
{
|
||||
path: "breach-report",
|
||||
component: BreachReportComponent,
|
||||
data: { titleId: "dataBreachReport" },
|
||||
},
|
||||
{
|
||||
path: "reused-passwords-report",
|
||||
component: ReusedPasswordsReportComponent,
|
||||
data: { titleId: "reusedPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "unsecured-websites-report",
|
||||
component: UnsecuredWebsitesReportComponent,
|
||||
data: { titleId: "unsecuredWebsitesReport" },
|
||||
},
|
||||
{
|
||||
path: "weak-passwords-report",
|
||||
component: WeakPasswordsReportComponent,
|
||||
data: { titleId: "weakPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "exposed-passwords-report",
|
||||
component: ExposedPasswordsReportComponent,
|
||||
data: { titleId: "exposedPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "inactive-two-factor-report",
|
||||
component: InactiveTwoFactorReportComponent,
|
||||
data: { titleId: "inactive2faReport" },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "reports",
|
||||
loadChildren: async () => (await import("./reports/reports.module")).ReportsModule,
|
||||
},
|
||||
{ path: "setup/families-for-enterprise", component: FamiliesForEnterpriseSetupComponent },
|
||||
],
|
||||
},
|
||||
|
@ -53,6 +53,7 @@ import localeZhTw from "@angular/common/locales/zh-Hant";
|
||||
import { NgModule } from "@angular/core";
|
||||
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { BadgeModule, ButtonModule } from "@bitwarden/components";
|
||||
import { InfiniteScrollModule } from "ngx-infinite-scroll";
|
||||
import { ToastrModule } from "ngx-toastr";
|
||||
|
||||
@ -78,6 +79,7 @@ import { VerifyRecoverDeleteComponent } from "./accounts/verify-recover-delete.c
|
||||
import { NestedCheckboxComponent } from "./components/nested-checkbox.component";
|
||||
import { PasswordRepromptComponent } from "./components/password-reprompt.component";
|
||||
import { PasswordStrengthComponent } from "./components/password-strength.component";
|
||||
import { PremiumBadgeComponent } from "./components/premium-badge.component";
|
||||
import { FooterComponent } from "./layouts/footer.component";
|
||||
import { FrontendLayoutComponent } from "./layouts/frontend-layout.component";
|
||||
import { NavbarComponent } from "./layouts/navbar.component";
|
||||
@ -135,6 +137,15 @@ import { CollectionsComponent as OrgCollectionsComponent } from "./organizations
|
||||
import { GroupingsComponent as OrgGroupingsComponent } from "./organizations/vault/groupings.component";
|
||||
import { VaultComponent as OrgVaultComponent } from "./organizations/vault/vault.component";
|
||||
import { ProvidersComponent } from "./providers/providers.component";
|
||||
import { BreachReportComponent } from "./reports/breach-report.component";
|
||||
import { ExposedPasswordsReportComponent } from "./reports/exposed-passwords-report.component";
|
||||
import { InactiveTwoFactorReportComponent } from "./reports/inactive-two-factor-report.component";
|
||||
import { ReportCardComponent } from "./reports/report-card.component";
|
||||
import { ReportListComponent } from "./reports/report-list.component";
|
||||
import { ReportsComponent } from "./reports/reports.component";
|
||||
import { ReusedPasswordsReportComponent } from "./reports/reused-passwords-report.component";
|
||||
import { UnsecuredWebsitesReportComponent } from "./reports/unsecured-websites-report.component";
|
||||
import { WeakPasswordsReportComponent } from "./reports/weak-passwords-report.component";
|
||||
import { AccessComponent } from "./send/access.component";
|
||||
import { AddEditComponent as SendAddEditComponent } from "./send/add-edit.component";
|
||||
import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component";
|
||||
@ -184,17 +195,11 @@ import { UserBillingComponent } from "./settings/user-billing.component";
|
||||
import { UserSubscriptionComponent } from "./settings/user-subscription.component";
|
||||
import { VaultTimeoutInputComponent } from "./settings/vault-timeout-input.component";
|
||||
import { VerifyEmailComponent } from "./settings/verify-email.component";
|
||||
import { BreachReportComponent } from "./tools/breach-report.component";
|
||||
import { ExportComponent } from "./tools/export.component";
|
||||
import { ExposedPasswordsReportComponent } from "./tools/exposed-passwords-report.component";
|
||||
import { ImportComponent } from "./tools/import.component";
|
||||
import { InactiveTwoFactorReportComponent } from "./tools/inactive-two-factor-report.component";
|
||||
import { PasswordGeneratorHistoryComponent } from "./tools/password-generator-history.component";
|
||||
import { PasswordGeneratorComponent } from "./tools/password-generator.component";
|
||||
import { ReusedPasswordsReportComponent } from "./tools/reused-passwords-report.component";
|
||||
import { ToolsComponent } from "./tools/tools.component";
|
||||
import { UnsecuredWebsitesReportComponent } from "./tools/unsecured-websites-report.component";
|
||||
import { WeakPasswordsReportComponent } from "./tools/weak-passwords-report.component";
|
||||
import { AddEditCustomFieldsComponent } from "./vault/add-edit-custom-fields.component";
|
||||
import { AddEditComponent } from "./vault/add-edit.component";
|
||||
import { AttachmentsComponent } from "./vault/attachments.component";
|
||||
@ -271,8 +276,11 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
ToastrModule,
|
||||
BadgeModule,
|
||||
ButtonModule,
|
||||
],
|
||||
declarations: [
|
||||
PremiumBadgeComponent,
|
||||
AcceptEmergencyComponent,
|
||||
AcceptOrganizationComponent,
|
||||
AccessComponent,
|
||||
@ -384,6 +392,9 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||
RecoverTwoFactorComponent,
|
||||
RegisterComponent,
|
||||
RemovePasswordComponent,
|
||||
ReportCardComponent,
|
||||
ReportListComponent,
|
||||
ReportsComponent,
|
||||
RequireSsoPolicyComponent,
|
||||
ResetPasswordPolicyComponent,
|
||||
ReusedPasswordsReportComponent,
|
||||
|
@ -17,7 +17,13 @@
|
||||
<small class="form-text text-muted">{{ "breachCheckUsernameEmail" | i18n }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<button
|
||||
bit-button
|
||||
buttonType="primary"
|
||||
class="btn-submit"
|
||||
type="submit"
|
||||
[disabled]="form.loading"
|
||||
>
|
||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||
<span>{{ "checkBreaches" | i18n }}</span>
|
||||
</button>
|
@ -2,7 +2,14 @@
|
||||
<h1>{{ "exposedPasswordsReport" | i18n }}</h1>
|
||||
</div>
|
||||
<p>{{ "exposedPasswordsReportDesc" | i18n }}</p>
|
||||
<button type="button" class="btn btn-primary btn-submit" [disabled]="loading" (click)="load()">
|
||||
<button
|
||||
bit-button
|
||||
buttonType="primary"
|
||||
type="button"
|
||||
class="btn-submit"
|
||||
[disabled]="loading"
|
||||
(click)="load()"
|
||||
>
|
||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||
<span>{{ "checkExposedPasswords" | i18n }}</span>
|
||||
</button>
|
25
src/app/reports/report-card.component.html
Normal file
25
src/app/reports/report-card.component.html
Normal file
@ -0,0 +1,25 @@
|
||||
<a
|
||||
class="tw-border tw-border-solid tw-border-secondary-300 tw-rounded tw-overflow-hidden tw-h-full tw-w-72 tw-block !tw-text-main hover:tw-no-underline hover:tw-scale-105 tw-transition-all focus:tw-outline-none focus:tw-ring focus:tw-ring-offset-2 focus:tw-ring-primary-700"
|
||||
[routerLink]="route"
|
||||
(click)="click()"
|
||||
>
|
||||
<div class="tw-relative">
|
||||
<div
|
||||
class="tw-text-center tw-h-28 tw-flex tw-bg-background-alt2 tw-text-primary-300"
|
||||
[ngClass]="{ 'tw-grayscale': premium }"
|
||||
>
|
||||
<div class="tw-m-auto" [innerHtml]="icon"></div>
|
||||
</div>
|
||||
<div class="tw-p-5" [ngClass]="{ 'tw-grayscale': report.requiresPremium }">
|
||||
<h3 class="tw-text-xl tw-font-bold tw-mb-4">{{ report.title | i18n }}</h3>
|
||||
<p class="tw-mb-0">{{ report.description | i18n }}</p>
|
||||
</div>
|
||||
<span
|
||||
bit-badge
|
||||
badgeType="success"
|
||||
class="tw-absolute tw-left-2 tw-top-2 tw-leading-none"
|
||||
*ngIf="premium"
|
||||
>{{ "premium" | i18n }}</span
|
||||
>
|
||||
</div>
|
||||
</a>
|
166
src/app/reports/report-card.component.ts
Normal file
166
src/app/reports/report-card.component.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
export enum ReportTypes {
|
||||
"exposedPasswords" = "exposedPasswords",
|
||||
"reusedPasswords" = "reusedPasswords",
|
||||
"weakPasswords" = "weakPasswords",
|
||||
"unsecuredWebsites" = "unsecuredWebsites",
|
||||
"inactive2fa" = "inactive2fa",
|
||||
"dataBreach" = "dataBreach",
|
||||
}
|
||||
|
||||
type ReportEntry = {
|
||||
title: string;
|
||||
description: string;
|
||||
route: string;
|
||||
icon: string;
|
||||
requiresPremium: boolean;
|
||||
};
|
||||
|
||||
const reports: Record<ReportTypes, ReportEntry> = {
|
||||
exposedPasswords: {
|
||||
title: "exposedPasswordsReport",
|
||||
description: "exposedPasswordsReportDesc",
|
||||
route: "exposed-passwords-report",
|
||||
icon: `
|
||||
<svg width="101" height="77" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.374 50.192a26.42 26.42 0 0 0 9.111 1.608c14.34 0 25.965-11.372 25.965-25.4 0-.337-.007-.673-.02-1.008h25.299v34.85H32.374v-10.05Z" fill="currentColor" />
|
||||
<path d="M15.805 26.4c0 14.028 11.625 25.4 25.965 25.4s25.964-11.372 25.964-25.4C67.734 12.372 56.11 1 41.77 1 27.43 1 15.805 12.372 15.805 26.4Z" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M27.914 47.849a1 1 0 0 0-2 0h2Zm68.288-26.792a2.12 2.12 0 0 1 2.14 2.11h2c0-2.253-1.83-4.11-4.14-4.11v2Zm2.14 2.11v40.552h2V23.167h-2Zm0 40.552c0 1.172-.958 2.11-2.14 2.11v2c2.25 0 4.14-1.798 4.14-4.11h-2Zm-2.14 2.11H30.054v2h66.148v-2Zm-66.148 0a2.12 2.12 0 0 1-2.14-2.11h-2a4.12 4.12 0 0 0 4.14 4.11v-2Zm-2.14-2.11V47.85h-2v15.87h2Zm39.254-42.662h29.034v-2H67.168v2Z" fill="#fff" />
|
||||
<path d="M67.203 25.56h25.64v34.85H32.487V50.011" stroke="#fff" stroke-width="2" stroke-linejoin="round" />
|
||||
<path d="M47.343 76h31.571" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M57.557 66.83V76M67.771 66.83V76" stroke="#fff" stroke-width="2" stroke-linejoin="round" />
|
||||
<path d="m20.995 42.873-3.972 3.972-14.61 14.61a3.413 3.413 0 0 0 0 4.826v0a3.413 3.413 0 0 0 4.827 0l14.61-14.61 3.972-3.972" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M86.037 32.488H71.845M86.037 37.81H76.28M71.845 37.81h-6.652M86.037 43.132h-6.209M74.95 43.132H61.2M86.037 48.454H71.845M66.967 48.454h-7.54M86.037 53.776H66.08M61.201 53.776h-11.53M44.793 53.776h-7.096" stroke="#fff" stroke-width="2" stroke-linecap="round" />
|
||||
<rect width="40.801" height="9.757" rx="4" transform="matrix(-1 0 0 1 61.201 14.748)" stroke="#fff" stroke-width="2" />
|
||||
<path d="M16.852 33.375h28.375a4 4 0 0 1 4 4v1.757a4 4 0 0 1-4 4H22.174M66.523 33.375h-3.539a4 4 0 0 0-4 4v3.761c0 1.102.894 1.996 1.996 1.996v0" stroke="#fff" stroke-width="2" stroke-linecap="round" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: true,
|
||||
},
|
||||
reusedPasswords: {
|
||||
title: "reusedPasswordsReport",
|
||||
description: "reusedPasswordsReportDesc",
|
||||
route: "reused-passwords-report",
|
||||
icon: `
|
||||
<svg width="102" height="102" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M57.983 15.06a35.664 35.664 0 0 1 14.531 6.27c16.164 11.78 19.585 34.613 7.643 51a37.227 37.227 0 0 1-6.81 7.138m-32.842 6.697a35.708 35.708 0 0 1-11.239-5.495c-16.163-11.78-19.585-34.613-7.642-51a37.55 37.55 0 0 1 3.295-3.929" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M93.909 64.598H7.72c-.708 0-1.275-.662-1.275-1.49V40.273c0-.828.567-1.49 1.275-1.49H93.91c.708 0 1.275.663 1.275 1.49v22.837c.047.827-.567 1.49-1.275 1.49Z" fill="currentColor" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M21.532 52.186v-5.965M21.532 52.187l5.748-1.844M21.532 52.186l3.524 4.881M21.531 52.186l-3.47 4.881M21.532 52.187l-5.694-1.844M40.944 52.186v-5.965M40.944 52.187l5.694-1.844M40.944 52.187l3.525 4.88M40.944 52.187l-3.525 4.88M40.944 52.187l-5.694-1.844M54.849 57.337h11.294M74.21 57.337h11.295M41.75 83l.71 4.75-4.75.71M58.664 18.66 56 14.665 59.996 12" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: true,
|
||||
},
|
||||
weakPasswords: {
|
||||
title: "weakPasswordsReport",
|
||||
description: "weakPasswordsReportDesc",
|
||||
route: "weak-passwords-report",
|
||||
icon: `
|
||||
<svg width="78" height="78" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M66.493 64.415V77H9.979V64.324M9.979 44.065V32.106h56.514v12.148" stroke="#fff" stroke-width="2" stroke-linejoin="round" />
|
||||
<path d="M75.44 64.852H2.085c-.603 0-1.085-.555-1.085-1.25V44.448c0-.694.482-1.25 1.085-1.25H75.44c.603 0 1.085.556 1.085 1.25v19.156c.04.694-.482 1.25-1.085 1.25Z" fill="currentColor" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M13.84 54.56v-5.077M13.84 54.56l4.893-1.57M13.84 54.56l3 4.153M13.84 54.56l-2.954 4.153M13.84 54.56l-4.846-1.57M30.363 54.56v-5.077M30.363 54.56l4.846-1.57M30.363 54.56l3 4.153M30.363 54.56l-3 4.153M30.363 54.56l-4.846-1.57M42.197 59.042h9.506M58.57 59.042h9.507" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M20.863 31.364c-.274-5.285 0-15.817 1.093-18.863 1.276-3.554 6.233-10.826 15.856-11.482 4.83-.273 15.2 2.296 18.043 14.763" stroke="#fff" stroke-width="2" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: true,
|
||||
},
|
||||
unsecuredWebsites: {
|
||||
title: "unsecuredWebsitesReport",
|
||||
description: "unsecuredWebsitesReportDesc",
|
||||
route: "unsecured-websites-report",
|
||||
icon: `
|
||||
<svg width="113" height="76" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.71 12.983h110.362v55.11a6 6 0 0 1-6 6H7.711a6 6 0 0 1-6-6v-55.11Z" fill="currentColor" />
|
||||
<rect x="1" y="1.073" width="110.5" height="73.454" rx="9" stroke="#fff" stroke-width="2" />
|
||||
<path d="M89.48 8.048V7.47M96.363 8.048V7.47M103.246 8.048V7.47" stroke="#fff" stroke-width="4" stroke-linecap="round" />
|
||||
<path d="M0 12.983h111.217" stroke="#fff" stroke-width="2" />
|
||||
<path d="m93.236 44.384-18.42-11.026 2.93 21.266 5.582-5.237 4.27 6.46 2.98-1.971-4.26-6.446 6.918-3.046Z" fill="#175DDC" stroke="#fff" stroke-width="2" stroke-linejoin="round" />
|
||||
<rect width="96.673" height="6.886" rx="3.443" transform="matrix(-1 0 0 1 104.373 18.721)" stroke="#fff" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: true,
|
||||
},
|
||||
inactive2fa: {
|
||||
title: "inactive2faReport",
|
||||
description: "inactive2faReportDesc",
|
||||
route: "inactive-two-factor-report",
|
||||
icon: `
|
||||
<svg width="42" height="75" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" stroke="#fff" stroke-width="2" d="M1 13.121h39.595v48.758H1z" />
|
||||
<rect x="1" y="1" width="39.595" height="73" rx="8" stroke="#fff" stroke-width="2" />
|
||||
<path stroke="#fff" stroke-width="2" stroke-linecap="round" d="M12.344 8.091h16.907M18.907 67.424h3.025M31.503 32.515c-2.047-4.337-6.717-7.061-11.73-6.414a11.356 11.356 0 0 0-9.125 7.126M10.816 42.016c2.047 4.337 6.718 7.062 11.73 6.414 4.346-.562 7.8-3.51 9.213-7.358" />
|
||||
<path d="m33.584 29.293-1.295 4.625-4.625-1.295M8.523 44.725l1.441-4.581 4.582 1.441" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: true,
|
||||
},
|
||||
dataBreach: {
|
||||
title: "dataBreachReport",
|
||||
description: "breachDesc",
|
||||
route: "breach-report",
|
||||
icon: `
|
||||
<svg width="58" height="75" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M39.569 74H13.007a7 7 0 0 1-7-7V31.077a7 7 0 0 1 7-7h19.101a7 7 0 0 1 4.988 2.088l7.46 7.576a7 7 0 0 1 2.013 4.912V67a7 7 0 0 1-7 7Z" fill="#175DDC" stroke="#fff" stroke-width="2" />
|
||||
<path d="M44.576 69.055H18.015a7 7 0 0 1-7-7V26.132a7 7 0 0 1 7-7h19.1a7 7 0 0 1 4.988 2.088l7.46 7.576a7 7 0 0 1 2.013 4.911v28.348a7 7 0 0 1-7 7Z" fill="#175DDC" stroke="#fff" stroke-width="2" />
|
||||
<path d="M50 63.698H23.439a7 7 0 0 1-7-7V20.775a7 7 0 0 1 7-7h19.1a7 7 0 0 1 4.988 2.088l7.46 7.575A7 7 0 0 1 57 28.35v28.348a7 7 0 0 1-7 7Z" fill="#175DDC" stroke="#fff" stroke-width="2" />
|
||||
<path d="M44.648 13.599v3.95a8 8 0 0 0 8 8h4.518" stroke="#fff" stroke-width="2" />
|
||||
<path stroke="#fff" stroke-width="2" stroke-linecap="round" d="M23.533 37.736H49.49M23.533 46.802H49.49M23.533 42.269H49.49M23.533 55.456H49.49M23.533 50.923H49.49" />
|
||||
<path d="M1 16.483C1 7.944 8.013 1 16.69 1c8.678 0 15.691 6.944 15.691 15.483 0 8.54-7.013 15.484-15.69 15.484C8.012 31.967 1 25.023 1 16.484Z" fill="#518FFF" stroke="#fff" stroke-width="2" />
|
||||
<path d="m16.562 7.979.1 11.538" stroke="#fff" stroke-width="2" stroke-linecap="round" />
|
||||
<ellipse rx="1.252" ry="1.236" transform="rotate(-.479 2802.219 -1964.476) skewX(.012)" fill="#fff" />
|
||||
</svg>
|
||||
`,
|
||||
requiresPremium: false,
|
||||
},
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-report-card",
|
||||
templateUrl: "report-card.component.html",
|
||||
})
|
||||
export class ReportCardComponent implements OnInit {
|
||||
@Input() type: ReportTypes;
|
||||
|
||||
report: ReportEntry;
|
||||
|
||||
hasPremium: boolean;
|
||||
|
||||
constructor(
|
||||
private stateService: StateService,
|
||||
private messagingService: MessagingService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.report = reports[this.type];
|
||||
|
||||
this.hasPremium = await this.stateService.getCanAccessPremium();
|
||||
}
|
||||
|
||||
get premium() {
|
||||
return this.report.requiresPremium && !this.hasPremium;
|
||||
}
|
||||
|
||||
get route() {
|
||||
if (this.premium) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.report.route;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.sanitizer.bypassSecurityTrustHtml(this.report.icon);
|
||||
}
|
||||
|
||||
click() {
|
||||
if (this.premium) {
|
||||
this.messagingService.send("premiumRequired");
|
||||
}
|
||||
}
|
||||
}
|
11
src/app/reports/report-list.component.html
Normal file
11
src/app/reports/report-list.component.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="page-header">
|
||||
<h1>{{ "reports" | i18n }}</h1>
|
||||
</div>
|
||||
|
||||
<p>{{ "reportsDesc" | i18n }}</p>
|
||||
|
||||
<div class="tw-inline-grid tw-grid-cols-3 tw-gap-4">
|
||||
<div *ngFor="let report of reports">
|
||||
<app-report-card [type]="report"></app-report-card>
|
||||
</div>
|
||||
</div>
|
18
src/app/reports/report-list.component.ts
Normal file
18
src/app/reports/report-list.component.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { ReportTypes } from "./report-card.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-report-list",
|
||||
templateUrl: "report-list.component.html",
|
||||
})
|
||||
export class ReportListComponent {
|
||||
reports = [
|
||||
ReportTypes.exposedPasswords,
|
||||
ReportTypes.reusedPasswords,
|
||||
ReportTypes.weakPasswords,
|
||||
ReportTypes.unsecuredWebsites,
|
||||
ReportTypes.inactive2fa,
|
||||
ReportTypes.dataBreach,
|
||||
];
|
||||
}
|
12
src/app/reports/reports.component.html
Normal file
12
src/app/reports/reports.component.html
Normal file
@ -0,0 +1,12 @@
|
||||
<div class="container page-content">
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col">
|
||||
<a bit-button routerLink="./" *ngIf="!homepage">
|
||||
<i class="bwi bwi-angle-left" aria-hidden="true"></i>
|
||||
{{ "backToReports" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
25
src/app/reports/reports.component.ts
Normal file
25
src/app/reports/reports.component.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Component, OnDestroy } from "@angular/core";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { Subscription } from "rxjs";
|
||||
import { filter } from "rxjs/operators";
|
||||
|
||||
@Component({
|
||||
selector: "app-reports",
|
||||
templateUrl: "reports.component.html",
|
||||
})
|
||||
export class ReportsComponent implements OnDestroy {
|
||||
homepage = true;
|
||||
subscription: Subscription;
|
||||
|
||||
constructor(router: Router) {
|
||||
this.subscription = router.events
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe((event) => {
|
||||
this.homepage = (event as NavigationEnd).url == "/reports";
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscription?.unsubscribe();
|
||||
}
|
||||
}
|
60
src/app/reports/reports.module.ts
Normal file
60
src/app/reports/reports.module.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { AuthGuardService } from "jslib-angular/services/auth-guard.service";
|
||||
|
||||
import { BreachReportComponent } from "./breach-report.component";
|
||||
import { ExposedPasswordsReportComponent } from "./exposed-passwords-report.component";
|
||||
import { InactiveTwoFactorReportComponent } from "./inactive-two-factor-report.component";
|
||||
import { ReportListComponent } from "./report-list.component";
|
||||
import { ReportsComponent } from "./reports.component";
|
||||
import { ReusedPasswordsReportComponent } from "./reused-passwords-report.component";
|
||||
import { UnsecuredWebsitesReportComponent } from "./unsecured-websites-report.component";
|
||||
import { WeakPasswordsReportComponent } from "./weak-passwords-report.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
component: ReportsComponent,
|
||||
canActivate: [AuthGuardService],
|
||||
children: [
|
||||
{ path: "", pathMatch: "full", component: ReportListComponent, data: { homepage: true } },
|
||||
{
|
||||
path: "breach-report",
|
||||
component: BreachReportComponent,
|
||||
data: { titleId: "dataBreachReport" },
|
||||
},
|
||||
{
|
||||
path: "reused-passwords-report",
|
||||
component: ReusedPasswordsReportComponent,
|
||||
data: { titleId: "reusedPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "unsecured-websites-report",
|
||||
component: UnsecuredWebsitesReportComponent,
|
||||
data: { titleId: "unsecuredWebsitesReport" },
|
||||
},
|
||||
{
|
||||
path: "weak-passwords-report",
|
||||
component: WeakPasswordsReportComponent,
|
||||
data: { titleId: "weakPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "exposed-passwords-report",
|
||||
component: ExposedPasswordsReportComponent,
|
||||
data: { titleId: "exposedPasswordsReport" },
|
||||
},
|
||||
{
|
||||
path: "inactive-two-factor-report",
|
||||
component: InactiveTwoFactorReportComponent,
|
||||
data: { titleId: "inactive2faReport" },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ReportsModule {}
|
@ -9,7 +9,7 @@
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="userAddEditTitle">
|
||||
<span class="badge badge-primary" *ngIf="readOnly">{{ "premium" | i18n }}</span>
|
||||
<app-premium-badge *ngIf="readOnly"></app-premium-badge>
|
||||
{{ title }}
|
||||
<small class="text-muted" *ngIf="name">{{ name }}</small>
|
||||
</h2>
|
||||
|
@ -15,15 +15,7 @@
|
||||
<div class="page-header d-flex">
|
||||
<h2>
|
||||
{{ "trustedEmergencyContacts" | i18n }}
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
class="badge badge-primary"
|
||||
*ngIf="!canAccessPremium"
|
||||
(click)="premiumRequired()"
|
||||
>
|
||||
{{ "premium" | i18n }}
|
||||
</a>
|
||||
<app-premium-badge></app-premium-badge>
|
||||
</h2>
|
||||
<div class="ml-auto d-flex">
|
||||
<button
|
||||
|
@ -39,15 +39,7 @@
|
||||
></i>
|
||||
<span class="sr-only">{{ "enabled" | i18n }}</span>
|
||||
</ng-container>
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
class="badge badge-primary"
|
||||
*ngIf="!canAccessPremium && p.premium"
|
||||
(click)="premiumRequired()"
|
||||
>
|
||||
{{ "premium" | i18n }}
|
||||
</a>
|
||||
<app-premium-badge *ngIf="p.premium"></app-premium-badge>
|
||||
</h3>
|
||||
{{ p.description }}
|
||||
</div>
|
||||
|
@ -15,59 +15,6 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header d-flex">
|
||||
{{ "reports" | i18n }}
|
||||
<div class="ml-auto">
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
class="badge badge-primary"
|
||||
*ngIf="!canAccessPremium"
|
||||
(click)="premiumRequired()"
|
||||
>
|
||||
{{ "premium" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a
|
||||
routerLink="exposed-passwords-report"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ "exposedPasswordsReport" | i18n }}
|
||||
</a>
|
||||
<a routerLink="reused-passwords-report" class="list-group-item" routerLinkActive="active">
|
||||
{{ "reusedPasswordsReport" | i18n }}
|
||||
</a>
|
||||
<a routerLink="weak-passwords-report" class="list-group-item" routerLinkActive="active">
|
||||
{{ "weakPasswordsReport" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
routerLink="unsecured-websites-report"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ "unsecuredWebsitesReport" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
routerLink="inactive-two-factor-report"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ "inactive2faReport" | i18n }}
|
||||
</a>
|
||||
<a routerLink="breach-report" class="list-group-item d-flex" routerLinkActive="active">
|
||||
{{ "dataBreachReport" | i18n }}
|
||||
<div class="ml-auto">
|
||||
<span class="badge badge-success" *ngIf="!canAccessPremium">
|
||||
{{ "free" | i18n | uppercase }}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<router-outlet></router-outlet>
|
||||
|
@ -187,15 +187,10 @@
|
||||
title="{{ 'verificationCodeTotp' | i18n }}"
|
||||
class="ml-2"
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
class="badge badge-primary ml-3"
|
||||
(click)="premiumRequired()"
|
||||
*ngIf="!organization && !cipher.organizationId && !canAccessPremium"
|
||||
>
|
||||
{{ "premium" | i18n }}
|
||||
</a>
|
||||
<app-premium-badge
|
||||
*ngIf="!organization && !cipher.organizationId"
|
||||
class="ml-3"
|
||||
></app-premium-badge>
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
|
@ -1430,11 +1430,14 @@
|
||||
"reports": {
|
||||
"message": "Reports"
|
||||
},
|
||||
"reportsDesc": {
|
||||
"message": "Identify and close security gaps in your online accounts by clicking the reports below."
|
||||
},
|
||||
"unsecuredWebsitesReport": {
|
||||
"message": "Unsecured Websites Report"
|
||||
"message": "Unsecure Websites"
|
||||
},
|
||||
"unsecuredWebsitesReportDesc": {
|
||||
"message": "Using unsecured websites with the http:// scheme can be dangerous. If the website allows, you should always access it using the https:// scheme so that your connection is encrypted."
|
||||
"message": "URLs that start with http:// don’t use the best available encryption. Change the Login URIs for these accounts to https:// for safer browsing."
|
||||
},
|
||||
"unsecuredWebsitesFound": {
|
||||
"message": "Unsecured Websites Found"
|
||||
@ -1452,10 +1455,10 @@
|
||||
"message": "No items in your vault have unsecured URIs."
|
||||
},
|
||||
"inactive2faReport": {
|
||||
"message": "Inactive 2FA Report"
|
||||
"message": "Inactive Two-step Login"
|
||||
},
|
||||
"inactive2faReportDesc": {
|
||||
"message": "Two-factor authentication (2FA) is an important security setting that helps secure your accounts. If the website offers it, you should always enable two-factor authentication."
|
||||
"message": "Two-step Login adds a layer of protection to your accounts. Turn on Two-Step Login using Bitwarden Authenticator for these accounts or use an alternative method."
|
||||
},
|
||||
"inactive2faFound": {
|
||||
"message": "Logins Without 2FA Found"
|
||||
@ -1476,10 +1479,10 @@
|
||||
"message": "Instructions"
|
||||
},
|
||||
"exposedPasswordsReport": {
|
||||
"message": "Exposed Passwords Report"
|
||||
"message": "Exposed Passwords"
|
||||
},
|
||||
"exposedPasswordsReportDesc": {
|
||||
"message": "Exposed passwords are passwords that have been uncovered in known data breaches that were released publicly or sold on the dark web by hackers."
|
||||
"message": "Passwords exposed in a data breach are easy targets for attackers. Change these passwords to prevent potential break-ins."
|
||||
},
|
||||
"exposedPasswordsFound": {
|
||||
"message": "Exposed Passwords Found"
|
||||
@ -1509,10 +1512,10 @@
|
||||
}
|
||||
},
|
||||
"weakPasswordsReport": {
|
||||
"message": "Weak Passwords Report"
|
||||
"message": "Weak Passwords"
|
||||
},
|
||||
"weakPasswordsReportDesc": {
|
||||
"message": "Weak passwords can easily be guessed by hackers and automated tools that are used to crack passwords. The Bitwarden password generator can help you create strong passwords."
|
||||
"message": "Weak passwords can be easily guessed by attackers. Change these passwords to strong ones using the Password Generator."
|
||||
},
|
||||
"weakPasswordsFound": {
|
||||
"message": "Weak Passwords Found"
|
||||
@ -1530,10 +1533,10 @@
|
||||
"message": "No items in your vault have weak passwords."
|
||||
},
|
||||
"reusedPasswordsReport": {
|
||||
"message": "Reused Passwords Report"
|
||||
"message": "Reused Passwords"
|
||||
},
|
||||
"reusedPasswordsReportDesc": {
|
||||
"message": "If a service that you use is compromised, reusing the same password elsewhere can allow hackers to easily gain access to more of your online accounts. You should use a unique password for every account or service."
|
||||
"message": "Reusing passwords makes it easier for attackers to break into multiple accounts. Change these passwords so that each is unique."
|
||||
},
|
||||
"reusedPasswordsFound": {
|
||||
"message": "Reused Passwords Found"
|
||||
@ -1560,10 +1563,10 @@
|
||||
}
|
||||
},
|
||||
"dataBreachReport": {
|
||||
"message": "Data Breach Report"
|
||||
"message": "Data Breach"
|
||||
},
|
||||
"breachDesc": {
|
||||
"message": "A \"breach\" is an incident where a site's data has been illegally accessed by hackers and then released publicly. Review the types of data that were compromised (email addresses, passwords, credit cards etc.) and take appropriate action, such as changing passwords."
|
||||
"message": "Breached accounts can expose your personal information. Secure breached accounts by enabling 2FA or creating a stronger password."
|
||||
},
|
||||
"breachCheckUsernameEmail": {
|
||||
"message": "Check any usernames or email addresses that you use."
|
||||
@ -4832,6 +4835,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"backToReports": {
|
||||
"message": "Back to Reports"
|
||||
},
|
||||
"generator": {
|
||||
"message": "Generator"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user