= {
+ exposedPasswords: {
+ title: "exposedPasswordsReport",
+ description: "exposedPasswordsReportDesc",
+ route: "exposed-passwords-report",
+ icon: `
+
+ `,
+ requiresPremium: true,
+ },
+ reusedPasswords: {
+ title: "reusedPasswordsReport",
+ description: "reusedPasswordsReportDesc",
+ route: "reused-passwords-report",
+ icon: `
+
+ `,
+ requiresPremium: true,
+ },
+ weakPasswords: {
+ title: "weakPasswordsReport",
+ description: "weakPasswordsReportDesc",
+ route: "weak-passwords-report",
+ icon: `
+
+ `,
+ requiresPremium: true,
+ },
+ unsecuredWebsites: {
+ title: "unsecuredWebsitesReport",
+ description: "unsecuredWebsitesReportDesc",
+ route: "unsecured-websites-report",
+ icon: `
+
+ `,
+ requiresPremium: true,
+ },
+ inactive2fa: {
+ title: "inactive2faReport",
+ description: "inactive2faReportDesc",
+ route: "inactive-two-factor-report",
+ icon: `
+
+ `,
+ requiresPremium: true,
+ },
+ dataBreach: {
+ title: "dataBreachReport",
+ description: "breachDesc",
+ route: "breach-report",
+ icon: `
+
+ `,
+ 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");
+ }
+ }
+}
diff --git a/src/app/reports/report-list.component.html b/src/app/reports/report-list.component.html
new file mode 100644
index 00000000..e3028731
--- /dev/null
+++ b/src/app/reports/report-list.component.html
@@ -0,0 +1,11 @@
+
+
+{{ "reportsDesc" | i18n }}
+
+
diff --git a/src/app/reports/report-list.component.ts b/src/app/reports/report-list.component.ts
new file mode 100644
index 00000000..48894984
--- /dev/null
+++ b/src/app/reports/report-list.component.ts
@@ -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,
+ ];
+}
diff --git a/src/app/reports/reports.component.html b/src/app/reports/reports.component.html
new file mode 100644
index 00000000..2978a9e6
--- /dev/null
+++ b/src/app/reports/reports.component.html
@@ -0,0 +1,12 @@
+
diff --git a/src/app/reports/reports.component.ts b/src/app/reports/reports.component.ts
new file mode 100644
index 00000000..c0e67ac5
--- /dev/null
+++ b/src/app/reports/reports.component.ts
@@ -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();
+ }
+}
diff --git a/src/app/reports/reports.module.ts b/src/app/reports/reports.module.ts
new file mode 100644
index 00000000..795c4c3b
--- /dev/null
+++ b/src/app/reports/reports.module.ts
@@ -0,0 +1,60 @@
+import { NgModule } from "@angular/core";
+import { RouterModule, Routes } from "@angular/router";
+
+import { AuthGuard } from "jslib-angular/guards/auth.guard";
+
+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: [AuthGuard],
+ 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 {}
diff --git a/src/app/tools/reused-passwords-report.component.html b/src/app/reports/reused-passwords-report.component.html
similarity index 100%
rename from src/app/tools/reused-passwords-report.component.html
rename to src/app/reports/reused-passwords-report.component.html
diff --git a/src/app/tools/reused-passwords-report.component.ts b/src/app/reports/reused-passwords-report.component.ts
similarity index 100%
rename from src/app/tools/reused-passwords-report.component.ts
rename to src/app/reports/reused-passwords-report.component.ts
diff --git a/src/app/tools/unsecured-websites-report.component.html b/src/app/reports/unsecured-websites-report.component.html
similarity index 100%
rename from src/app/tools/unsecured-websites-report.component.html
rename to src/app/reports/unsecured-websites-report.component.html
diff --git a/src/app/tools/unsecured-websites-report.component.ts b/src/app/reports/unsecured-websites-report.component.ts
similarity index 100%
rename from src/app/tools/unsecured-websites-report.component.ts
rename to src/app/reports/unsecured-websites-report.component.ts
diff --git a/src/app/tools/weak-passwords-report.component.html b/src/app/reports/weak-passwords-report.component.html
similarity index 100%
rename from src/app/tools/weak-passwords-report.component.html
rename to src/app/reports/weak-passwords-report.component.html
diff --git a/src/app/tools/weak-passwords-report.component.ts b/src/app/reports/weak-passwords-report.component.ts
similarity index 100%
rename from src/app/tools/weak-passwords-report.component.ts
rename to src/app/reports/weak-passwords-report.component.ts
diff --git a/src/app/tools/tools.component.html b/src/app/tools/tools.component.html
index 9f94f784..e6155d57 100644
--- a/src/app/tools/tools.component.html
+++ b/src/app/tools/tools.component.html
@@ -15,51 +15,6 @@
-
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index c9b5bceb..29be1458 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -1428,11 +1428,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"
@@ -1450,10 +1453,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"
@@ -1474,10 +1477,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"
@@ -1507,10 +1510,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"
@@ -1528,10 +1531,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"
@@ -1558,10 +1561,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."
@@ -4830,6 +4833,9 @@
}
}
},
+ "backToReports": {
+ "message": "Back to Reports"
+ },
"masterPassword": {
"message": "Master Password"
},