diff --git a/jslib b/jslib index e55926336c..e10523cc61 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit e55926336c0fc2362d3aa791dc9fe385d03f6ae8 +Subproject commit e10523cc6115d94a199f0c3342c5d8040304f7f8 diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index c624f52bfe..fd663f5c96 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -33,6 +33,9 @@ import { } from './organizations/settings/two-factor-setup.component'; import { ExportComponent as OrgExportComponent } from './organizations/tools/export.component'; +import { + ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent, +} from './organizations/tools/exposed-passwords-report.component'; import { ImportComponent as OrgImportComponent } from './organizations/tools/import.component'; import { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component'; @@ -198,6 +201,11 @@ const routes: Routes = [ { path: '', pathMatch: 'full', redirectTo: 'import' }, { path: 'import', component: OrgImportComponent, data: { titleId: 'importData' } }, { path: 'export', component: OrgExportComponent, data: { titleId: 'exportVault' } }, + { + path: 'exposed-passwords-report', + component: OrgExposedPasswordsReportComponent, + data: { titleId: 'exposedPasswordsReport' }, + }, ], }, { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0042298cd4..10bdcb353c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -63,6 +63,9 @@ import { } from './organizations/settings/two-factor-setup.component'; import { ExportComponent as OrgExportComponent } from './organizations/tools/export.component'; +import { + ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent, +} from './organizations/tools/exposed-passwords-report.component'; import { ImportComponent as OrgImportComponent } from './organizations/tools/import.component'; import { ToolsComponent as OrgToolsComponent } from './organizations/tools/tools.component'; @@ -252,6 +255,7 @@ registerLocaleData(localeZhCn, 'zh-CN'); OrgEntityUsersComponent, OrgEventsComponent, OrgExportComponent, + OrgExposedPasswordsReportComponent, OrgImportComponent, OrgGroupAddEditComponent, OrgGroupingsComponent, diff --git a/src/app/organizations/tools/exposed-passwords-report.component.ts b/src/app/organizations/tools/exposed-passwords-report.component.ts new file mode 100644 index 0000000000..7103807c2c --- /dev/null +++ b/src/app/organizations/tools/exposed-passwords-report.component.ts @@ -0,0 +1,39 @@ +import { + Component, + ComponentFactoryResolver, +} from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { AuditService } from 'jslib/abstractions/audit.service'; +import { CipherService } from 'jslib/abstractions/cipher.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; +import { UserService } from 'jslib/abstractions/user.service'; + +import { + ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent, +} from '../../tools/exposed-passwords-report.component'; + +import { CipherView } from 'jslib/models/view/cipherView'; + +@Component({ + selector: 'app-exposed-passwords-report', + templateUrl: '../../tools/exposed-passwords-report.component.html', +}) +export class ExposedPasswordsReportComponent extends BaseExposedPasswordsReportComponent { + constructor(ciphersService: CipherService, auditService: AuditService, + componentFactoryResolver: ComponentFactoryResolver, messagingService: MessagingService, + userService: UserService, private route: ActivatedRoute) { + super(ciphersService, auditService, componentFactoryResolver, messagingService, userService); + } + + ngOnInit() { + this.route.parent.parent.params.subscribe(async (params) => { + this.organization = await this.userService.getOrganization(params.organizationId); + super.ngOnInit(); + }); + } + + getAllCiphers(): Promise { + return this.cipherService.getAllFromApiForOrganization(this.organization.id); + } +} diff --git a/src/app/organizations/tools/tools.component.html b/src/app/organizations/tools/tools.component.html index 5b2d2ba79b..0b0e5ff91d 100644 --- a/src/app/organizations/tools/tools.component.html +++ b/src/app/organizations/tools/tools.component.html @@ -1,7 +1,7 @@
-
diff --git a/src/app/organizations/tools/tools.component.ts b/src/app/organizations/tools/tools.component.ts index 3aa3be4b55..82f632e600 100644 --- a/src/app/organizations/tools/tools.component.ts +++ b/src/app/organizations/tools/tools.component.ts @@ -1,7 +1,27 @@ import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { Organization } from 'jslib/models/domain/organization'; + +import { UserService } from 'jslib/abstractions/user.service'; @Component({ selector: 'app-org-tools', templateUrl: 'tools.component.html', }) -export class ToolsComponent { } +export class ToolsComponent { + organization: Organization; + accessReports = false; + + constructor(private route: ActivatedRoute, private userService: UserService) { } + + ngOnInit() { + this.route.parent.params.subscribe(async (params) => { + this.organization = await this.userService.getOrganization(params.organizationId); + // TODO: Maybe we want to just make sure they are not on a free plan? Just compare use2fa for now + // since all paid plans include use2fa + this.accessReports = this.organization.use2fa; + }); + } + +} diff --git a/src/app/organizations/vault/ciphers.component.ts b/src/app/organizations/vault/ciphers.component.ts index 9ba64aaacd..abf4fc9ee4 100644 --- a/src/app/organizations/vault/ciphers.component.ts +++ b/src/app/organizations/vault/ciphers.component.ts @@ -45,21 +45,7 @@ export class CiphersComponent extends BaseCiphersComponent { return; } this.accessEvents = this.organization.useEvents; - const ciphers = await this.apiService.getCiphersOrganization(this.organization.id); - if (ciphers != null && ciphers.data != null && ciphers.data.length) { - const decCiphers: CipherView[] = []; - const promises: any[] = []; - ciphers.data.forEach((r) => { - const data = new CipherData(r); - const cipher = new Cipher(data); - promises.push(cipher.decrypt().then((c) => decCiphers.push(c))); - }); - await Promise.all(promises); - decCiphers.sort(this.cipherService.getLocaleSortingFunction()); - this.allCiphers = decCiphers; - } else { - this.allCiphers = []; - } + this.allCiphers = await this.cipherService.getAllFromApiForOrganization(this.organization.id); this.applyFilter(filter); this.loaded = true; } diff --git a/src/app/tools/cipher-report.component.ts b/src/app/tools/cipher-report.component.ts index 238bb93704..ad8010f659 100644 --- a/src/app/tools/cipher-report.component.ts +++ b/src/app/tools/cipher-report.component.ts @@ -6,7 +6,10 @@ import { import { CipherView } from 'jslib/models/view/cipherView'; +import { Organization } from 'jslib/models/domain/organization'; + import { ModalComponent } from '../modal.component'; +import { AddEditComponent as OrgAddEditComponent } from '../organizations/vault/add-edit.component'; import { AddEditComponent } from '../vault/add-edit.component'; import { MessagingService } from 'jslib/abstractions/messaging.service'; @@ -18,11 +21,12 @@ export class CipherReportComponent { loading = false; hasLoaded = false; ciphers: CipherView[] = []; + organization: Organization; private modal: ModalComponent = null; constructor(private componentFactoryResolver: ComponentFactoryResolver, protected userService: UserService, - protected messagingService: MessagingService, public requiresPremium: boolean) { } + protected messagingService: MessagingService, public requiresPaid: boolean) { } async load() { this.loading = true; @@ -38,10 +42,18 @@ export class CipherReportComponent { const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent); this.modal = this.cipherAddEditModalRef.createComponent(factory).instance; - const childComponent = this.modal.show( - AddEditComponent, this.cipherAddEditModalRef); + let childComponent: OrgAddEditComponent | AddEditComponent; + if (this.organization != null) { + childComponent = this.modal.show(OrgAddEditComponent, this.cipherAddEditModalRef); + (childComponent as OrgAddEditComponent).organization = this.organization; + } else { + childComponent = this.modal.show(AddEditComponent, this.cipherAddEditModalRef); + } childComponent.cipherId = cipher == null ? null : cipher.id; + if (this.organization != null) { + childComponent.organizationId = this.organization.id; + } childComponent.onSavedCipher.subscribe(async (c: CipherView) => { this.modal.close(); await this.load(); @@ -58,12 +70,21 @@ export class CipherReportComponent { return childComponent; } - protected async checkPremium(): Promise { - const accessPremium = await this.userService.canAccessPremium(); - if (this.requiresPremium && !accessPremium) { - this.messagingService.send('premiumRequired'); - this.loading = false; - return false; + protected async checkAccess(): Promise { + if (this.organization != null) { + // TODO: Maybe we want to just make sure they are not on a free plan? Just compare use2fa for now + // since all paid plans include use2fa + if (this.requiresPaid && !this.organization.use2fa) { + this.messagingService.send('upgradeOrganization', { organizationId: this.organization.id }); + return false; + } + } else { + const accessPremium = await this.userService.canAccessPremium(); + if (this.requiresPaid && !accessPremium) { + this.messagingService.send('premiumRequired'); + this.loading = false; + return false; + } } return true; } diff --git a/src/app/tools/exposed-passwords-report.component.ts b/src/app/tools/exposed-passwords-report.component.ts index 2b01cec703..61a27f34e2 100644 --- a/src/app/tools/exposed-passwords-report.component.ts +++ b/src/app/tools/exposed-passwords-report.component.ts @@ -22,24 +22,24 @@ import { CipherReportComponent } from './cipher-report.component'; export class ExposedPasswordsReportComponent extends CipherReportComponent implements OnInit { exposedPasswordMap = new Map(); - constructor(private ciphersService: CipherService, private auditService: AuditService, + constructor(protected cipherService: CipherService, protected auditService: AuditService, componentFactoryResolver: ComponentFactoryResolver, messagingService: MessagingService, userService: UserService) { super(componentFactoryResolver, userService, messagingService, true); } ngOnInit() { - this.checkPremium(); + this.checkAccess(); } async load() { - if (await this.checkPremium()) { + if (await this.checkAccess()) { super.load(); } } async setCiphers() { - const allCiphers = await this.ciphersService.getAllDecrypted(); + const allCiphers = await this.getAllCiphers(); const exposedPasswordCiphers: CipherView[] = []; const promises: Array> = []; allCiphers.forEach((c) => { @@ -57,4 +57,8 @@ export class ExposedPasswordsReportComponent extends CipherReportComponent imple await Promise.all(promises); this.ciphers = exposedPasswordCiphers; } + + protected getAllCiphers(): Promise { + return this.cipherService.getAllDecrypted(); + } } diff --git a/src/app/tools/inactive-two-factor-report.component.ts b/src/app/tools/inactive-two-factor-report.component.ts index 5c4e4e1a25..68460ac12c 100644 --- a/src/app/tools/inactive-two-factor-report.component.ts +++ b/src/app/tools/inactive-two-factor-report.component.ts @@ -30,7 +30,7 @@ export class InactiveTwoFactorReportComponent extends CipherReportComponent impl } async ngOnInit() { - if (await this.checkPremium()) { + if (await this.checkAccess()) { await super.load(); } } diff --git a/src/app/tools/reused-passwords-report.component.ts b/src/app/tools/reused-passwords-report.component.ts index 08c7886c61..a82ffe707f 100644 --- a/src/app/tools/reused-passwords-report.component.ts +++ b/src/app/tools/reused-passwords-report.component.ts @@ -27,7 +27,7 @@ export class ReusedPasswordsReportComponent extends CipherReportComponent implem } async ngOnInit() { - if (await this.checkPremium()) { + if (await this.checkAccess()) { await super.load(); } } diff --git a/src/app/tools/unsecured-websites-report.component.ts b/src/app/tools/unsecured-websites-report.component.ts index 0becbaf524..3620334d4e 100644 --- a/src/app/tools/unsecured-websites-report.component.ts +++ b/src/app/tools/unsecured-websites-report.component.ts @@ -23,7 +23,7 @@ export class UnsecuredWebsitesReportComponent extends CipherReportComponent impl } async ngOnInit() { - if (await this.checkPremium()) { + if (await this.checkAccess()) { await super.load(); } } diff --git a/src/app/tools/weak-passwords-report.component.ts b/src/app/tools/weak-passwords-report.component.ts index 73e8bb6e21..b7852942cb 100644 --- a/src/app/tools/weak-passwords-report.component.ts +++ b/src/app/tools/weak-passwords-report.component.ts @@ -31,7 +31,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen } async ngOnInit() { - if (await this.checkPremium()) { + if (await this.checkAccess()) { await super.load(); } }