1
0
mirror of https://github.com/bitwarden/web synced 2025-12-10 05:13:40 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Matt Gibson
5a2068bf54 specify an allowed host 2022-05-16 11:48:22 -04:00
Matt Gibson
3d3198d86f Allow all hosts for dev environment
This is needed to enable testing of hCaptcha through a host proxy.
2022-05-16 10:34:26 -04:00
62 changed files with 598 additions and 783 deletions

View File

@@ -19,8 +19,8 @@ jobs:
name: Setup name: Setup
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
outputs: outputs:
release_version: ${{ steps.version.outputs.version }} release_version: ${{ steps.version.outputs.package }}
tag_version: ${{ steps.version.outputs.version }} tag_version: ${{ steps.version.outputs.tag }}
branch_name: ${{ steps.branch.outputs.branch_name }} branch_name: ${{ steps.branch.outputs.branch_name }}
steps: steps:
- name: Branch check - name: Branch check
@@ -38,11 +38,20 @@ jobs:
- name: Check Release Version - name: Check Release Version
id: version id: version
uses: bitwarden/gh-actions/release-version-check@ea9fab01d76940267b4147cc1c4542431246b9f6 run: |
with: version=$( jq -r ".version" package.json)
release-type: ${{ github.event.inputs.release_type }} previous_release_tag_version=$(
project-type: ts curl -sL https://api.github.com/repos/$GITHUB_REPOSITORY/releases/latest | jq -r ".tag_name"
file: package.json )
if [ "v$version" == "$previous_release_tag_version" ] && \
[ "${{ github.event.inputs.release_type }}" == "Initial Release" ]; then
echo "[!] Already released v$version. Please bump version to continue"
exit 1
fi
echo "::set-output name=package::$version"
echo "::set-output name=tag::v$version"
- name: Get branch name - name: Get branch name
id: branch id: branch

View File

@@ -22,16 +22,14 @@ const routes: Routes = [
component: ManageComponent, component: ManageComponent,
canActivate: [PermissionsGuard], canActivate: [PermissionsGuard],
data: { data: {
permissions: NavigationPermissionsService.getPermissions("manage"), permissions: NavigationPermissionsService.getPermissions("manage").concat(
Permissions.ManageSso
),
}, },
children: [ children: [
{ {
path: "sso", path: "sso",
component: SsoComponent, component: SsoComponent,
canActivate: [PermissionsGuard],
data: {
permissions: [Permissions.ManageSso],
},
}, },
], ],
}, },

View File

@@ -1,9 +1,11 @@
import { CommonModule } from "@angular/common";
import { ComponentFactoryResolver, NgModule } from "@angular/core"; import { ComponentFactoryResolver, NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { JslibModule } from "jslib-angular/jslib.module";
import { ModalService } from "jslib-angular/services/modal.service"; import { ModalService } from "jslib-angular/services/modal.service";
import { LayoutsModule } from "src/app/layouts/layouts.module"; import { OssModule } from "src/app/oss.module";
import { SharedModule } from "src/app/modules/shared.module";
import { AddOrganizationComponent } from "./clients/add-organization.component"; import { AddOrganizationComponent } from "./clients/add-organization.component";
import { ClientsComponent } from "./clients/clients.component"; import { ClientsComponent } from "./clients/clients.component";
@@ -26,7 +28,7 @@ import { SetupProviderComponent } from "./setup/setup-provider.component";
import { SetupComponent } from "./setup/setup.component"; import { SetupComponent } from "./setup/setup.component";
@NgModule({ @NgModule({
imports: [SharedModule, LayoutsModule, ProvidersRoutingModule], imports: [CommonModule, FormsModule, OssModule, JslibModule, ProvidersRoutingModule],
declarations: [ declarations: [
AcceptProviderComponent, AcceptProviderComponent,
AccountComponent, AccountComponent,

View File

@@ -3,6 +3,7 @@
"notifications": "http://localhost:61840" "notifications": "http://localhost:61840"
}, },
"dev": { "dev": {
"allowedHosts": "bitwarden.local",
"proxyApi": "http://localhost:4000", "proxyApi": "http://localhost:4000",
"proxyIdentity": "http://localhost:33656", "proxyIdentity": "http://localhost:33656",
"proxyEvents": "http://localhost:46273", "proxyEvents": "http://localhost:46273",

2
jslib

Submodule jslib updated: 0d658ba26d...65584c6496

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "@bitwarden/web-vault", "name": "@bitwarden/web-vault",
"version": "2022.05.0", "version": "2.28.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@bitwarden/web-vault", "name": "@bitwarden/web-vault",
"version": "2022.05.0", "version": "2.28.1",
"hasInstallScript": true, "hasInstallScript": true,
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {

View File

@@ -1,6 +1,6 @@
{ {
"name": "@bitwarden/web-vault", "name": "@bitwarden/web-vault",
"version": "2022.05.0", "version": "2.28.1",
"license": "GPL-3.0", "license": "GPL-3.0",
"repository": "https://github.com/bitwarden/web", "repository": "https://github.com/bitwarden/web",
"scripts": { "scripts": {

View File

@@ -101,7 +101,7 @@
<div [ngClass]="{ 'col-5': layout, 'col-12': !layout }"> <div [ngClass]="{ 'col-5': layout, 'col-12': !layout }">
<div class="row justify-content-md-center mt-5"> <div class="row justify-content-md-center mt-5">
<div [ngClass]="{ 'col-5': !layout, 'col-12': layout }"> <div [ngClass]="{ 'col-5': !layout, 'col-12': layout }">
<h1 class="lead text-center mb-4" *ngIf="!layout">{{ "createAccount" | i18n }}</h1> <p class="lead text-center mb-4" *ngIf="!layout">{{ "createAccount" | i18n }}</p>
<div class="card d-block"> <div class="card d-block">
<div class="card-body"> <div class="card-body">
<app-callout <app-callout

View File

@@ -122,20 +122,17 @@ export abstract class BaseEventsComponent {
const userId = r.actingUserId == null ? r.userId : r.actingUserId; const userId = r.actingUserId == null ? r.userId : r.actingUserId;
const eventInfo = await this.eventService.getEventInfo(r); const eventInfo = await this.eventService.getEventInfo(r);
const user = this.getUserName(r, userId); const user = this.getUserName(r, userId);
const userName = user != null ? user.name : this.i18nService.t("unknown");
return new EventView({ return new EventView({
message: eventInfo.message, message: eventInfo.message,
humanReadableMessage: eventInfo.humanReadableMessage, humanReadableMessage: eventInfo.humanReadableMessage,
appIcon: eventInfo.appIcon, appIcon: eventInfo.appIcon,
appName: eventInfo.appName, appName: eventInfo.appName,
userId: userId, userId: userId,
userName: r.installationId != null ? `Installation: ${r.installationId}` : userName, userName: user != null ? user.name : this.i18nService.t("unknown"),
userEmail: user != null ? user.email : "", userEmail: user != null ? user.email : "",
date: r.date, date: r.date,
ip: r.ipAddress, ip: r.ipAddress,
type: r.type, type: r.type,
installationId: r.installationId,
}); });
}) })
); );

View File

@@ -5,7 +5,7 @@ import { OrganizationService } from "jslib-common/abstractions/organization.serv
import { Utils } from "jslib-common/misc/utils"; import { Utils } from "jslib-common/misc/utils";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { NavigationPermissionsService } from "../services/navigation-permissions.service"; import { NavigationPermissionsService } from "../organizations/services/navigation-permissions.service";
@Component({ @Component({
selector: "app-organization-switcher", selector: "app-organization-switcher",

View File

@@ -1,6 +1,6 @@
<div class="container footer text-muted"> <div class="container footer text-muted">
<div class="row"> <div class="row">
<div class="col">&copy; {{ year }} Bitwarden Inc.</div> <div class="col">&copy; {{ year }}, Bitwarden Inc.</div>
<div class="col text-center"></div> <div class="col text-center"></div>
<div class="col text-right"> <div class="col text-right">
{{ "versionNumber" | i18n: version }} {{ "versionNumber" | i18n: version }}

View File

@@ -1,5 +1,5 @@
<router-outlet></router-outlet> <router-outlet></router-outlet>
<div class="container my-5 text-muted text-center"> <div class="container my-5 text-muted text-center">
&copy; {{ year }} Bitwarden Inc. <br /> &copy; {{ year }}, Bitwarden Inc. <br />
{{ "versionNumber" | i18n: version }} {{ "versionNumber" | i18n: version }}
</div> </div>

View File

@@ -1,13 +0,0 @@
import { NgModule } from "@angular/core";
import { FooterComponent } from "../layouts/footer.component";
import { FrontendLayoutComponent } from "../layouts/frontend-layout.component";
import { NavbarComponent } from "../layouts/navbar.component";
import { SharedModule } from "../modules/shared.module";
@NgModule({
imports: [SharedModule],
declarations: [NavbarComponent, FooterComponent, FrontendLayoutComponent],
exports: [NavbarComponent, FooterComponent],
})
export class LayoutsModule {}

View File

@@ -20,10 +20,66 @@ import { UpdateTempPasswordComponent } from "../accounts/update-temp-password.co
import { VerifyEmailTokenComponent } from "../accounts/verify-email-token.component"; import { VerifyEmailTokenComponent } from "../accounts/verify-email-token.component";
import { VerifyRecoverDeleteComponent } from "../accounts/verify-recover-delete.component"; import { VerifyRecoverDeleteComponent } from "../accounts/verify-recover-delete.component";
import { NestedCheckboxComponent } from "../components/nested-checkbox.component"; import { NestedCheckboxComponent } from "../components/nested-checkbox.component";
import { OrganizationSwitcherComponent } from "../components/organization-switcher.component";
import { PasswordRepromptComponent } from "../components/password-reprompt.component"; import { PasswordRepromptComponent } from "../components/password-reprompt.component";
import { PasswordStrengthComponent } from "../components/password-strength.component";
import { PremiumBadgeComponent } from "../components/premium-badge.component"; import { PremiumBadgeComponent } from "../components/premium-badge.component";
import { LayoutsModule } from "../layouts/layouts.module"; import { FooterComponent } from "../layouts/footer.component";
import { FrontendLayoutComponent } from "../layouts/frontend-layout.component";
import { NavbarComponent } from "../layouts/navbar.component";
import { UserLayoutComponent } from "../layouts/user-layout.component"; import { UserLayoutComponent } from "../layouts/user-layout.component";
import { OrganizationLayoutComponent } from "../organizations/layouts/organization-layout.component";
import { BulkConfirmComponent as OrgBulkConfirmComponent } from "../organizations/manage/bulk/bulk-confirm.component";
import { BulkRemoveComponent as OrgBulkRemoveComponent } from "../organizations/manage/bulk/bulk-remove.component";
import { BulkStatusComponent as OrgBulkStatusComponent } from "../organizations/manage/bulk/bulk-status.component";
import { CollectionAddEditComponent as OrgCollectionAddEditComponent } from "../organizations/manage/collection-add-edit.component";
import { CollectionsComponent as OrgManageCollectionsComponent } from "../organizations/manage/collections.component";
import { EntityEventsComponent as OrgEntityEventsComponent } from "../organizations/manage/entity-events.component";
import { EventsComponent as OrgEventsComponent } from "../organizations/manage/events.component";
import { GroupAddEditComponent as OrgGroupAddEditComponent } from "../organizations/manage/group-add-edit.component";
import { GroupsComponent as OrgGroupsComponent } from "../organizations/manage/groups.component";
import { ManageComponent as OrgManageComponent } from "../organizations/manage/manage.component";
import { PeopleComponent as OrgPeopleComponent } from "../organizations/manage/people.component";
import { PoliciesComponent as OrgPoliciesComponent } from "../organizations/manage/policies.component";
import { PolicyEditComponent as OrgPolicyEditComponent } from "../organizations/manage/policy-edit.component";
import { ResetPasswordComponent as OrgResetPasswordComponent } from "../organizations/manage/reset-password.component";
import { UserAddEditComponent as OrgUserAddEditComponent } from "../organizations/manage/user-add-edit.component";
import { UserConfirmComponent as OrgUserConfirmComponent } from "../organizations/manage/user-confirm.component";
import { UserGroupsComponent as OrgUserGroupsComponent } from "../organizations/manage/user-groups.component";
import { DisableSendPolicyComponent } from "../organizations/policies/disable-send.component";
import { MasterPasswordPolicyComponent } from "../organizations/policies/master-password.component";
import { PasswordGeneratorPolicyComponent } from "../organizations/policies/password-generator.component";
import { PersonalOwnershipPolicyComponent } from "../organizations/policies/personal-ownership.component";
import { RequireSsoPolicyComponent } from "../organizations/policies/require-sso.component";
import { ResetPasswordPolicyComponent } from "../organizations/policies/reset-password.component";
import { SendOptionsPolicyComponent } from "../organizations/policies/send-options.component";
import { SingleOrgPolicyComponent } from "../organizations/policies/single-org.component";
import { TwoFactorAuthenticationPolicyComponent } from "../organizations/policies/two-factor-authentication.component";
import { AccountComponent as OrgAccountComponent } from "../organizations/settings/account.component";
import { AdjustSubscription } from "../organizations/settings/adjust-subscription.component";
import { BillingSyncApiKeyComponent } from "../organizations/settings/billing-sync-api-key.component";
import { ChangePlanComponent } from "../organizations/settings/change-plan.component";
import { DeleteOrganizationComponent } from "../organizations/settings/delete-organization.component";
import { DownloadLicenseComponent } from "../organizations/settings/download-license.component";
import { ImageSubscriptionHiddenComponent as OrgSubscriptionHiddenComponent } from "../organizations/settings/image-subscription-hidden.component";
import { OrganizationBillingComponent } from "../organizations/settings/organization-billing.component";
import { OrganizationSubscriptionComponent } from "../organizations/settings/organization-subscription.component";
import { SettingsComponent as OrgSettingComponent } from "../organizations/settings/settings.component";
import { TwoFactorSetupComponent as OrgTwoFactorSetupComponent } from "../organizations/settings/two-factor-setup.component";
import { AcceptFamilySponsorshipComponent } from "../organizations/sponsorships/accept-family-sponsorship.component";
import { FamiliesForEnterpriseSetupComponent } from "../organizations/sponsorships/families-for-enterprise-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 { InactiveTwoFactorReportComponent as OrgInactiveTwoFactorReportComponent } from "../organizations/tools/inactive-two-factor-report.component";
import { ReusedPasswordsReportComponent as OrgReusedPasswordsReportComponent } from "../organizations/tools/reused-passwords-report.component";
import { ToolsComponent as OrgToolsComponent } from "../organizations/tools/tools.component";
import { UnsecuredWebsitesReportComponent as OrgUnsecuredWebsitesReportComponent } from "../organizations/tools/unsecured-websites-report.component";
import { WeakPasswordsReportComponent as OrgWeakPasswordsReportComponent } from "../organizations/tools/weak-passwords-report.component";
import { AddEditComponent as OrgAddEditComponent } from "../organizations/vault/add-edit.component";
import { AttachmentsComponent as OrgAttachmentsComponent } from "../organizations/vault/attachments.component";
import { CiphersComponent as OrgCiphersComponent } from "../organizations/vault/ciphers.component";
import { CollectionsComponent as OrgCollectionsComponent } from "../organizations/vault/collections.component";
import { ProvidersComponent } from "../providers/providers.component"; import { ProvidersComponent } from "../providers/providers.component";
import { BreachReportComponent } from "../reports/breach-report.component"; import { BreachReportComponent } from "../reports/breach-report.component";
import { ExposedPasswordsReportComponent } from "../reports/exposed-passwords-report.component"; import { ExposedPasswordsReportComponent } from "../reports/exposed-passwords-report.component";
@@ -58,7 +114,10 @@ import { EmergencyAccessTakeoverComponent } from "../settings/emergency-access-t
import { EmergencyAccessViewComponent } from "../settings/emergency-access-view.component"; import { EmergencyAccessViewComponent } from "../settings/emergency-access-view.component";
import { EmergencyAccessComponent } from "../settings/emergency-access.component"; import { EmergencyAccessComponent } from "../settings/emergency-access.component";
import { EmergencyAddEditComponent } from "../settings/emergency-add-edit.component"; import { EmergencyAddEditComponent } from "../settings/emergency-add-edit.component";
import { LinkSsoComponent } from "../settings/link-sso.component";
import { OrganizationPlansComponent } from "../settings/organization-plans.component";
import { PaymentMethodComponent } from "../settings/payment-method.component"; import { PaymentMethodComponent } from "../settings/payment-method.component";
import { PaymentComponent } from "../settings/payment.component";
import { PreferencesComponent } from "../settings/preferences.component"; import { PreferencesComponent } from "../settings/preferences.component";
import { PremiumComponent } from "../settings/premium.component"; import { PremiumComponent } from "../settings/premium.component";
import { ProfileComponent } from "../settings/profile.component"; import { ProfileComponent } from "../settings/profile.component";
@@ -110,10 +169,11 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
// Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left. // Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left.
// If you are building new functionality, please create or extend a feature module instead. // If you are building new functionality, please create or extend a feature module instead.
@NgModule({ @NgModule({
imports: [SharedModule, VaultFilterModule, OrganizationBadgeModule, PipesModule, LayoutsModule], imports: [SharedModule, VaultFilterModule, OrganizationBadgeModule, PipesModule],
declarations: [ declarations: [
PremiumBadgeComponent, PremiumBadgeComponent,
AcceptEmergencyComponent, AcceptEmergencyComponent,
AcceptFamilySponsorshipComponent,
AcceptOrganizationComponent, AcceptOrganizationComponent,
AccessComponent, AccessComponent,
AccountComponent, AccountComponent,
@@ -123,8 +183,10 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
AddEditCustomFieldsComponent, AddEditCustomFieldsComponent,
AdjustPaymentComponent, AdjustPaymentComponent,
AdjustStorageComponent, AdjustStorageComponent,
AdjustSubscription,
ApiKeyComponent, ApiKeyComponent,
AttachmentsComponent, AttachmentsComponent,
BillingSyncApiKeyComponent,
BillingSyncKeyComponent, BillingSyncKeyComponent,
BreachReportComponent, BreachReportComponent,
BulkActionsComponent, BulkActionsComponent,
@@ -135,12 +197,16 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
ChangeEmailComponent, ChangeEmailComponent,
ChangeKdfComponent, ChangeKdfComponent,
ChangePasswordComponent, ChangePasswordComponent,
ChangePlanComponent,
CiphersComponent, CiphersComponent,
CollectionsComponent, CollectionsComponent,
CreateOrganizationComponent, CreateOrganizationComponent,
DeauthorizeSessionsComponent, DeauthorizeSessionsComponent,
DeleteAccountComponent, DeleteAccountComponent,
DeleteOrganizationComponent,
DisableSendPolicyComponent,
DomainRulesComponent, DomainRulesComponent,
DownloadLicenseComponent,
EmergencyAccessAddEditComponent, EmergencyAccessAddEditComponent,
EmergencyAccessAttachmentsComponent, EmergencyAccessAttachmentsComponent,
EmergencyAccessComponent, EmergencyAccessComponent,
@@ -150,17 +216,65 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
EmergencyAddEditComponent, EmergencyAddEditComponent,
ExportComponent, ExportComponent,
ExposedPasswordsReportComponent, ExposedPasswordsReportComponent,
FamiliesForEnterpriseSetupComponent,
FolderAddEditComponent, FolderAddEditComponent,
FooterComponent,
FrontendLayoutComponent,
HintComponent, HintComponent,
ImportComponent, ImportComponent,
InactiveTwoFactorReportComponent, InactiveTwoFactorReportComponent,
LinkSsoComponent,
LockComponent, LockComponent,
LoginComponent, LoginComponent,
MasterPasswordPolicyComponent,
NavbarComponent,
NestedCheckboxComponent, NestedCheckboxComponent,
OrganizationSwitcherComponent,
OrgAccountComponent,
OrgAddEditComponent,
OrganizationBillingComponent,
OrganizationLayoutComponent,
OrganizationPlansComponent,
OrganizationSubscriptionComponent,
OrgAttachmentsComponent,
OrgBulkConfirmComponent,
OrgBulkRemoveComponent,
OrgBulkStatusComponent,
OrgCiphersComponent,
OrgCollectionAddEditComponent,
OrgCollectionsComponent,
OrgEntityEventsComponent,
OrgEventsComponent,
OrgExportComponent,
OrgExposedPasswordsReportComponent,
OrgGroupAddEditComponent,
OrgGroupsComponent,
OrgImportComponent,
OrgInactiveTwoFactorReportComponent,
OrgManageCollectionsComponent,
OrgManageComponent,
OrgPeopleComponent,
OrgPoliciesComponent,
OrgPolicyEditComponent,
OrgResetPasswordComponent,
OrgReusedPasswordsReportComponent,
OrgSettingComponent,
OrgToolsComponent,
OrgTwoFactorSetupComponent,
OrgSubscriptionHiddenComponent,
OrgUnsecuredWebsitesReportComponent,
OrgUserAddEditComponent,
OrgUserConfirmComponent,
OrgUserGroupsComponent,
OrgWeakPasswordsReportComponent,
GeneratorComponent, GeneratorComponent,
PasswordGeneratorHistoryComponent, PasswordGeneratorHistoryComponent,
PasswordGeneratorPolicyComponent,
PasswordRepromptComponent, PasswordRepromptComponent,
PasswordStrengthComponent,
PaymentComponent,
PaymentMethodComponent, PaymentMethodComponent,
PersonalOwnershipPolicyComponent,
PreferencesComponent, PreferencesComponent,
PremiumBadgeComponent, PremiumBadgeComponent,
PremiumComponent, PremiumComponent,
@@ -174,21 +288,26 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
ReportCardComponent, ReportCardComponent,
ReportListComponent, ReportListComponent,
ReportsComponent, ReportsComponent,
RequireSsoPolicyComponent,
ResetPasswordPolicyComponent,
ReusedPasswordsReportComponent, ReusedPasswordsReportComponent,
SecurityComponent, SecurityComponent,
SecurityKeysComponent, SecurityKeysComponent,
SendAddEditComponent, SendAddEditComponent,
SendComponent, SendComponent,
SendEffluxDatesComponent, SendEffluxDatesComponent,
SendOptionsPolicyComponent,
SetPasswordComponent, SetPasswordComponent,
SettingsComponent, SettingsComponent,
ShareComponent, ShareComponent,
SingleOrgPolicyComponent,
SponsoredFamiliesComponent, SponsoredFamiliesComponent,
SponsoringOrgRowComponent, SponsoringOrgRowComponent,
SsoComponent, SsoComponent,
SubscriptionComponent, SubscriptionComponent,
TaxInfoComponent, TaxInfoComponent,
ToolsComponent, ToolsComponent,
TwoFactorAuthenticationPolicyComponent,
TwoFactorAuthenticatorComponent, TwoFactorAuthenticatorComponent,
TwoFactorComponent, TwoFactorComponent,
TwoFactorDuoComponent, TwoFactorDuoComponent,
@@ -226,6 +345,7 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
AddEditCustomFieldsComponent, AddEditCustomFieldsComponent,
AdjustPaymentComponent, AdjustPaymentComponent,
AdjustStorageComponent, AdjustStorageComponent,
AdjustSubscription,
ApiKeyComponent, ApiKeyComponent,
AttachmentsComponent, AttachmentsComponent,
BreachReportComponent, BreachReportComponent,
@@ -237,12 +357,16 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
ChangeEmailComponent, ChangeEmailComponent,
ChangeKdfComponent, ChangeKdfComponent,
ChangePasswordComponent, ChangePasswordComponent,
ChangePlanComponent,
CiphersComponent, CiphersComponent,
CollectionsComponent, CollectionsComponent,
CreateOrganizationComponent, CreateOrganizationComponent,
DeauthorizeSessionsComponent, DeauthorizeSessionsComponent,
DeleteAccountComponent, DeleteAccountComponent,
DeleteOrganizationComponent,
DisableSendPolicyComponent,
DomainRulesComponent, DomainRulesComponent,
DownloadLicenseComponent,
EmergencyAccessAddEditComponent, EmergencyAccessAddEditComponent,
EmergencyAccessAttachmentsComponent, EmergencyAccessAttachmentsComponent,
EmergencyAccessComponent, EmergencyAccessComponent,
@@ -252,17 +376,64 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
EmergencyAddEditComponent, EmergencyAddEditComponent,
ExportComponent, ExportComponent,
ExposedPasswordsReportComponent, ExposedPasswordsReportComponent,
FamiliesForEnterpriseSetupComponent,
FolderAddEditComponent, FolderAddEditComponent,
FooterComponent,
FrontendLayoutComponent,
HintComponent, HintComponent,
ImportComponent, ImportComponent,
InactiveTwoFactorReportComponent, InactiveTwoFactorReportComponent,
LinkSsoComponent,
LockComponent, LockComponent,
LoginComponent, LoginComponent,
MasterPasswordPolicyComponent,
NavbarComponent,
NestedCheckboxComponent, NestedCheckboxComponent,
OrganizationSwitcherComponent,
OrgAccountComponent,
OrgAddEditComponent,
OrganizationBillingComponent,
OrganizationLayoutComponent,
OrganizationPlansComponent,
OrganizationSubscriptionComponent,
OrgAttachmentsComponent,
OrgBulkConfirmComponent,
OrgBulkRemoveComponent,
OrgBulkStatusComponent,
OrgCiphersComponent,
OrgCollectionAddEditComponent,
OrgCollectionsComponent,
OrgEntityEventsComponent,
OrgEventsComponent,
OrgExportComponent,
OrgExposedPasswordsReportComponent,
OrgGroupAddEditComponent,
OrgGroupsComponent,
OrgImportComponent,
OrgInactiveTwoFactorReportComponent,
OrgManageCollectionsComponent,
OrgManageComponent,
OrgPeopleComponent,
OrgPoliciesComponent,
OrgPolicyEditComponent,
OrgResetPasswordComponent,
OrgReusedPasswordsReportComponent,
OrgSettingComponent,
OrgToolsComponent,
OrgTwoFactorSetupComponent,
OrgUnsecuredWebsitesReportComponent,
OrgUserAddEditComponent,
OrgUserConfirmComponent,
OrgUserGroupsComponent,
OrgWeakPasswordsReportComponent,
GeneratorComponent, GeneratorComponent,
PasswordGeneratorHistoryComponent, PasswordGeneratorHistoryComponent,
PasswordGeneratorPolicyComponent,
PasswordRepromptComponent, PasswordRepromptComponent,
PasswordStrengthComponent,
PaymentComponent,
PaymentMethodComponent, PaymentMethodComponent,
PersonalOwnershipPolicyComponent,
PreferencesComponent, PreferencesComponent,
PremiumBadgeComponent, PremiumBadgeComponent,
PremiumComponent, PremiumComponent,
@@ -276,21 +447,26 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga
ReportCardComponent, ReportCardComponent,
ReportListComponent, ReportListComponent,
ReportsComponent, ReportsComponent,
RequireSsoPolicyComponent,
ResetPasswordPolicyComponent,
ReusedPasswordsReportComponent, ReusedPasswordsReportComponent,
SecurityComponent, SecurityComponent,
SecurityKeysComponent, SecurityKeysComponent,
SendAddEditComponent, SendAddEditComponent,
SendComponent, SendComponent,
SendEffluxDatesComponent, SendEffluxDatesComponent,
SendOptionsPolicyComponent,
SetPasswordComponent, SetPasswordComponent,
SettingsComponent, SettingsComponent,
ShareComponent, ShareComponent,
SingleOrgPolicyComponent,
SponsoredFamiliesComponent, SponsoredFamiliesComponent,
SponsoringOrgRowComponent, SponsoringOrgRowComponent,
SsoComponent, SsoComponent,
SubscriptionComponent, SubscriptionComponent,
TaxInfoComponent, TaxInfoComponent,
ToolsComponent, ToolsComponent,
TwoFactorAuthenticationPolicyComponent,
TwoFactorAuthenticatorComponent, TwoFactorAuthenticatorComponent,
TwoFactorComponent, TwoFactorComponent,
TwoFactorDuoComponent, TwoFactorDuoComponent,

View File

@@ -1,59 +0,0 @@
<div
class="modal fade"
role="dialog"
aria-modal="true"
aria-labelledby="enrollMasterPasswordResetTitle"
>
<div class="modal-dialog modal-dialog-scrollable" role="document">
<form
class="modal-content"
#form
(ngSubmit)="submit()"
[appApiAction]="formPromise"
ngNativeValidate
>
<div class="modal-header">
<h2 class="modal-title" id="enrollMasterPasswordResetTitle">
{{ (isEnrolled ? "withdrawPasswordReset" : "enrollPasswordReset") | i18n }}
</h2>
<button
type="button"
class="close"
data-dismiss="modal"
appA11yTitle="{{ 'close' | i18n }}"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<app-callout type="warning" *ngIf="!isEnrolled">
{{ "resetPasswordEnrollmentWarning" | i18n }}
</app-callout>
<app-user-verification [(ngModel)]="verification" name="secret"> </app-user-verification>
</div>
<div class="modal-footer">
<button bit-button buttonType="primary" type="submit" [disabled]="form.loading">
<i
class="bwi bwi-spinner bwi-spin"
title="{{ 'loading' | i18n }}"
*ngIf="form.loading"
></i>
<span>
{{ "submit" | i18n }}
</span>
</button>
<button
bit-button
buttonType="secondary"
type="button"
data-dismiss="modal"
appA11yTitle="{{ 'close' | i18n }}"
>
<span>
{{ "cancel" | i18n }}
</span>
</button>
</div>
</form>
</div>
</div>

View File

@@ -1,97 +0,0 @@
import { Component } from "@angular/core";
import { ModalRef } from "jslib-angular/components/modal/modal.ref";
import { ModalConfig } from "jslib-angular/services/modal.service";
import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SyncService } from "jslib-common/abstractions/sync.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { Utils } from "jslib-common/misc/utils";
import { Organization } from "jslib-common/models/domain/organization";
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
import { Verification } from "jslib-common/types/verification";
@Component({
selector: "app-enroll-master-password-reset",
templateUrl: "enroll-master-password-reset.component.html",
})
export class EnrollMasterPasswordReset {
organization: Organization;
verification: Verification;
formPromise: Promise<any>;
constructor(
private userVerificationService: UserVerificationService,
private apiService: ApiService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private cryptoService: CryptoService,
private syncService: SyncService,
private logService: LogService,
private modalRef: ModalRef,
config: ModalConfig
) {
this.organization = config.data.organization;
}
async submit() {
let toastStringRef = "withdrawPasswordResetSuccess";
this.formPromise = this.userVerificationService
.buildRequest(this.verification, OrganizationUserResetPasswordEnrollmentRequest)
.then(async (request) => {
// Set variables
let keyString: string = null;
// Enrolling
if (!this.organization.resetPasswordEnrolled) {
// Retrieve Public Key
const orgKeys = await this.apiService.getOrganizationKeys(this.organization.id);
if (orgKeys == null) {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
}
const publicKey = Utils.fromB64ToArray(orgKeys.publicKey);
// RSA Encrypt user's encKey.key with organization public key
const encKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
keyString = encryptedKey.encryptedString;
toastStringRef = "enrollPasswordResetSuccess";
// Create request and execute enrollment
request.resetPasswordKey = keyString;
await this.apiService.putOrganizationUserResetPasswordEnrollment(
this.organization.id,
this.organization.userId,
request
);
} else {
// Withdrawal
request.resetPasswordKey = keyString;
await this.apiService.putOrganizationUserResetPasswordEnrollment(
this.organization.id,
this.organization.userId,
request
);
}
await this.syncService.fullSync(true);
});
try {
await this.formPromise;
this.platformUtilsService.showToast("success", null, this.i18nService.t(toastStringRef));
this.modalRef.close();
} catch (e) {
this.logService.error(e);
}
}
get isEnrolled(): boolean {
return this.organization.resetPasswordEnrolled;
}
}

View File

@@ -1,14 +0,0 @@
import { ScrollingModule } from "@angular/cdk/scrolling";
import { NgModule } from "@angular/core";
import { LooseComponentsModule } from "../../loose-components.module";
import { SharedModule } from "../../shared.module";
import { EnrollMasterPasswordReset } from "./enroll-master-password-reset.component";
@NgModule({
imports: [SharedModule, ScrollingModule, LooseComponentsModule],
declarations: [EnrollMasterPasswordReset],
exports: [EnrollMasterPasswordReset],
})
export class OrganizationUserModule {}

View File

@@ -59,10 +59,6 @@ import { ToastrModule } from "ngx-toastr";
import { JslibModule } from "jslib-angular/jslib.module"; import { JslibModule } from "jslib-angular/jslib.module";
import { PasswordStrengthComponent } from "../components/password-strength.component";
import { OrganizationPlansComponent } from "../settings/organization-plans.component";
import { PaymentComponent } from "../settings/payment.component";
registerLocaleData(localeAf, "af"); registerLocaleData(localeAf, "af");
registerLocaleData(localeAz, "az"); registerLocaleData(localeAz, "az");
registerLocaleData(localeBe, "be"); registerLocaleData(localeBe, "be");
@@ -131,7 +127,6 @@ registerLocaleData(localeZhTw, "zh-TW");
ButtonModule, ButtonModule,
MenuModule, MenuModule,
], ],
declarations: [PasswordStrengthComponent, OrganizationPlansComponent, PaymentComponent],
exports: [ exports: [
CommonModule, CommonModule,
DragDropModule, DragDropModule,
@@ -147,9 +142,6 @@ registerLocaleData(localeZhTw, "zh-TW");
BadgeModule, BadgeModule,
ButtonModule, ButtonModule,
MenuModule, MenuModule,
PasswordStrengthComponent,
OrganizationPlansComponent,
PaymentComponent,
], ],
providers: [DatePipe], providers: [DatePipe],
bootstrap: [], bootstrap: [],

View File

@@ -16,7 +16,7 @@
aria-hidden="true" aria-hidden="true"
></i> ></i>
</button> </button>
<h3 class="filter-title">&nbsp;{{ collectionsGrouping.name | i18n }}</h3> <h3 class="filter-title">{{ collectionsGrouping.name | i18n }}</h3>
</div> </div>
<ul id="collection-filters" *ngIf="!isCollapsed(collectionsGrouping)" class="filter-options"> <ul id="collection-filters" *ngIf="!isCollapsed(collectionsGrouping)" class="filter-options">
<ng-template #recursiveCollections let-collections> <ng-template #recursiveCollections let-collections>
@@ -31,7 +31,7 @@
<button <button
class="toggle-button" class="toggle-button"
*ngIf="c.children.length" *ngIf="c.children.length"
(click)="toggleCollapse(c.node)" (click)="collapse(c.node)"
title="{{ 'toggleCollapse' | i18n }}" title="{{ 'toggleCollapse' | i18n }}"
[attr.aria-expanded]="!isCollapsed(c.node)" [attr.aria-expanded]="!isCollapsed(c.node)"
[attr.aria-controls]="c.node.name + '_children'" [attr.aria-controls]="c.node.name + '_children'"
@@ -51,7 +51,7 @@
class="bwi bwi-collection bwi-fw" class="bwi bwi-collection bwi-fw"
aria-hidden="true" aria-hidden="true"
></i ></i
>&nbsp;{{ c.node.name }} >{{ c.node.name }}
</button> </button>
</span> </span>
<ul <ul

View File

@@ -1,4 +1,4 @@
<ng-container *ngIf="!hide"> <ng-container *ngIf="!hide && !activeFilter.selectedOrganizationId">
<div class="filter-heading"> <div class="filter-heading">
<button <button
class="toggle-button" class="toggle-button"
@@ -16,7 +16,9 @@
}" }"
></i> ></i>
</button> </button>
<h3 class="filter-title">&nbsp;{{ "folders" | i18n }}</h3> <h3 class="filter-title">
{{ "folders" | i18n }}
</h3>
<button <button
class="text-muted ml-auto add-button" class="text-muted ml-auto add-button"
(click)="addFolder()" (click)="addFolder()"
@@ -54,7 +56,7 @@
</button> </button>
<button class="filter-button" (click)="applyFilter(f.node)"> <button class="filter-button" (click)="applyFilter(f.node)">
<i *ngIf="f.children.length === 0" class="bwi bwi-fw bwi-folder" aria-hidden="true"></i <i *ngIf="f.children.length === 0" class="bwi bwi-fw bwi-folder" aria-hidden="true"></i
>&nbsp;{{ f.node.name }} >{{ f.node.name }}
</button> </button>
<button <button
class="edit-button" class="edit-button"

View File

@@ -14,7 +14,7 @@
<span class="filter-buttons"> <span class="filter-buttons">
<a href="#" routerLink="/create-organization" class="filter-button"> <a href="#" routerLink="/create-organization" class="filter-button">
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i> <i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
&nbsp;{{ "newOrganization" | i18n }} {{ "newOrganization" | i18n }}
</a> </a>
</span> </span>
</li> </li>
@@ -45,6 +45,14 @@
> >
&nbsp;{{ organizationGrouping.name | i18n }} &nbsp;{{ organizationGrouping.name | i18n }}
</button> </button>
<a
href="#"
routerLink="/create-organization"
class="text-muted ml-auto create-organization-link"
appA11yTitle="{{ 'newOrganization' | i18n }}"
>
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
</a>
</div> </div>
<ul id="organization-filters" *ngIf="!isCollapsed" class="filter-options"> <ul id="organization-filters" *ngIf="!isCollapsed" class="filter-options">
<li <li
@@ -67,14 +75,6 @@
</ng-container> </ng-container>
</span> </span>
</li> </li>
<li class="filter-option">
<span class="filter-buttons">
<a href="#" routerLink="/create-organization" class="filter-button">
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
&nbsp;{{ "newOrganization" | i18n }}
</a>
</span>
</li>
</ul> </ul>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'singleOrganizationAndPersonalOwnershipPolicies'"> <ng-container *ngSwitchCase="'singleOrganizationAndPersonalOwnershipPolicies'">
@@ -85,7 +85,7 @@
</button> </button>
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchDefault> <ng-container *ngSwitchCase="'organizationMember'">
<div class="filter-heading"> <div class="filter-heading">
<button <button
class="toggle-button" class="toggle-button"
@@ -110,6 +110,14 @@
> >
&nbsp;{{ organizationGrouping.name | i18n }} &nbsp;{{ organizationGrouping.name | i18n }}
</button> </button>
<a
href="#"
routerLink="/create-organization"
class="text-muted ml-auto create-organization-link"
appA11yTitle="{{ 'newOrganization' | i18n }}"
>
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
</a>
</div> </div>
<ul id="organization-filters" *ngIf="!isCollapsed" class="filter-options"> <ul id="organization-filters" *ngIf="!isCollapsed" class="filter-options">
<li class="filter-option" [ngClass]="{ active: activeFilter.myVaultOnly }"> <li class="filter-option" [ngClass]="{ active: activeFilter.myVaultOnly }">
@@ -140,14 +148,6 @@
</ng-container> </ng-container>
</span> </span>
</li> </li>
<li class="filter-option" *ngIf="!(displayMode === 'singleOrganizationPolicy')">
<span class="filter-buttons">
<a href="#" routerLink="/create-organization" class="filter-button">
<i class="bwi bwi-plus bwi-fw" aria-hidden="true"></i>
&nbsp;{{ "newOrganization" | i18n }}
</a>
</span>
</li>
</ul> </ul>
</ng-container> </ng-container>
</ng-container> </ng-container>

View File

@@ -1,17 +1,17 @@
import { Component, Input } from "@angular/core"; import { Component, Input } from "@angular/core";
import { ModalService } from "jslib-angular/services/modal.service";
import { ApiService } from "jslib-common/abstractions/api.service"; import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service"; import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SyncService } from "jslib-common/abstractions/sync.service"; import { SyncService } from "jslib-common/abstractions/sync.service";
import { PolicyType } from "jslib-common/enums/policyType"; import { PolicyType } from "jslib-common/enums/policyType";
import { Utils } from "jslib-common/misc/utils";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { Policy } from "jslib-common/models/domain/policy"; import { Policy } from "jslib-common/models/domain/policy";
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
import { EnrollMasterPasswordReset } from "../../organizations/users/enroll-master-password-reset.component";
@Component({ @Component({
selector: "app-organization-options", selector: "app-organization-options",
@@ -29,8 +29,8 @@ export class OrganizationOptionsComponent {
private i18nService: I18nService, private i18nService: I18nService,
private apiService: ApiService, private apiService: ApiService,
private syncService: SyncService, private syncService: SyncService,
private cryptoService: CryptoService,
private policyService: PolicyService, private policyService: PolicyService,
private modalService: ModalService,
private logService: LogService private logService: LogService
) {} ) {}
@@ -82,7 +82,6 @@ export class OrganizationOptionsComponent {
this.platformUtilsService.showToast("success", null, "Unlinked SSO"); this.platformUtilsService.showToast("success", null, "Unlinked SSO");
await this.load(); await this.load();
} catch (e) { } catch (e) {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
this.logService.error(e); this.logService.error(e);
} }
} }
@@ -107,17 +106,74 @@ export class OrganizationOptionsComponent {
this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization")); this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization"));
await this.load(); await this.load();
} catch (e) { } catch (e) {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
this.logService.error(e); this.logService.error(e);
} }
} }
async toggleResetPasswordEnrollment(org: Organization) { async toggleResetPasswordEnrollment(org: Organization) {
this.modalService.open(EnrollMasterPasswordReset, { // Set variables
allowMultipleModals: true, let keyString: string = null;
data: { let toastStringRef = "withdrawPasswordResetSuccess";
organization: org,
}, // Enrolling
}); if (!org.resetPasswordEnrolled) {
// Alert user about enrollment
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("resetPasswordEnrollmentWarning"),
null,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return;
}
// Retrieve Public Key
this.actionPromise = this.apiService
.getOrganizationKeys(org.id)
.then(async (response) => {
if (response == null) {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
}
const publicKey = Utils.fromB64ToArray(response.publicKey);
// RSA Encrypt user's encKey.key with organization public key
const encKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(encKey.key, publicKey.buffer);
keyString = encryptedKey.encryptedString;
toastStringRef = "enrollPasswordResetSuccess";
// Create request and execute enrollment
const request = new OrganizationUserResetPasswordEnrollmentRequest();
request.resetPasswordKey = keyString;
return this.apiService.putOrganizationUserResetPasswordEnrollment(
org.id,
org.userId,
request
);
})
.then(() => {
return this.syncService.fullSync(true);
});
} else {
// Withdrawal
const request = new OrganizationUserResetPasswordEnrollmentRequest();
request.resetPasswordKey = keyString;
this.actionPromise = this.apiService
.putOrganizationUserResetPasswordEnrollment(org.id, org.userId, request)
.then(() => {
return this.syncService.fullSync(true);
});
}
try {
await this.actionPromise;
this.platformUtilsService.showToast("success", null, this.i18nService.t(toastStringRef));
await this.load();
} catch (e) {
this.logService.error(e);
}
} }
} }

View File

@@ -15,7 +15,9 @@
}" }"
></i> ></i>
</button> </button>
<h3>&nbsp;{{ "types" | i18n }}</h3> <h3>
{{ "types" | i18n }}
</h3>
</div> </div>
<ul id="type-filters" *ngIf="!isCollapsed" class="filter-options"> <ul id="type-filters" *ngIf="!isCollapsed" class="filter-options">
<li <li
@@ -24,14 +26,14 @@
> >
<span class="filter-buttons"> <span class="filter-buttons">
<button class="filter-button" (click)="applyFilter(cipherTypeEnum.Login)"> <button class="filter-button" (click)="applyFilter(cipherTypeEnum.Login)">
<i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>&nbsp;{{ "typeLogin" | i18n }} <i class="bwi bwi-fw bwi-globe" aria-hidden="true"></i>{{ "typeLogin" | i18n }}
</button> </button>
</span> </span>
</li> </li>
<li class="filter-option" [ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.Card }"> <li class="filter-option" [ngClass]="{ active: activeFilter.cipherType === cipherTypeEnum.Card }">
<span class="filter-buttons"> <span class="filter-buttons">
<button class="filter-button" (click)="applyFilter(cipherTypeEnum.Card)"> <button class="filter-button" (click)="applyFilter(cipherTypeEnum.Card)">
<i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i>&nbsp;{{ "typeCard" | i18n }} <i class="bwi bwi-fw bwi-credit-card" aria-hidden="true"></i>{{ "typeCard" | i18n }}
</button> </button>
</span> </span>
</li> </li>
@@ -41,7 +43,7 @@
> >
<span class="filter-buttons"> <span class="filter-buttons">
<button class="filter-button" (click)="applyFilter(cipherTypeEnum.Identity)"> <button class="filter-button" (click)="applyFilter(cipherTypeEnum.Identity)">
<i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i>&nbsp;{{ "typeIdentity" | i18n }} <i class="bwi bwi-fw bwi-id-card" aria-hidden="true"></i>{{ "typeIdentity" | i18n }}
</button> </button>
</span> </span>
</li> </li>
@@ -51,9 +53,7 @@
> >
<span class="filter-buttons"> <span class="filter-buttons">
<button class="filter-button" (click)="applyFilter(cipherTypeEnum.SecureNote)"> <button class="filter-button" (click)="applyFilter(cipherTypeEnum.SecureNote)">
<i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i>&nbsp;{{ <i class="bwi bwi-fw bwi-sticky-note" aria-hidden="true"></i>{{ "typeSecureNote" | i18n }}
"typeSecureNote" | i18n
}}
</button> </button>
</span> </span>
</li> </li>

View File

@@ -28,6 +28,16 @@ export class VaultFilterComponent extends BaseVaultFilterComponent {
this.onSearchTextChanged.emit(this.searchText); this.onSearchTextChanged.emit(this.searchText);
} }
// This method exists because the vault component gets its data mixed up during the initial sync on first login. It looks for data before the sync is complete.
// It should be removed as soon as doing so makes sense.
async reloadOrganizations() {
this.organizations = await this.vaultFilterService.buildOrganizations();
this.activePersonalOwnershipPolicy =
await this.vaultFilterService.checkForPersonalOwnershipPolicy();
this.activeSingleOrganizationPolicy =
await this.vaultFilterService.checkForSingleOrganizationPolicy();
}
async initCollections() { async initCollections() {
return await this.vaultFilterService.buildCollections(this.organization?.id); return await this.vaultFilterService.buildCollections(this.organization?.id);
} }

View File

@@ -12,7 +12,6 @@ import { SharedModule } from "../shared.module";
import { CollectionFilterComponent } from "./components/collection-filter.component"; import { CollectionFilterComponent } from "./components/collection-filter.component";
import { FolderFilterComponent } from "./components/folder-filter.component"; import { FolderFilterComponent } from "./components/folder-filter.component";
import { LinkSsoComponent } from "./components/link-sso.component";
import { OrganizationFilterComponent } from "./components/organization-filter.component"; import { OrganizationFilterComponent } from "./components/organization-filter.component";
import { OrganizationOptionsComponent } from "./components/organization-options.component"; import { OrganizationOptionsComponent } from "./components/organization-options.component";
import { StatusFilterComponent } from "./components/status-filter.component"; import { StatusFilterComponent } from "./components/status-filter.component";
@@ -29,7 +28,6 @@ import { VaultFilterComponent } from "./vault-filter.component";
OrganizationOptionsComponent, OrganizationOptionsComponent,
StatusFilterComponent, StatusFilterComponent,
TypeFilterComponent, TypeFilterComponent,
LinkSsoComponent,
], ],
exports: [VaultFilterComponent], exports: [VaultFilterComponent],
providers: [ providers: [

View File

@@ -58,6 +58,7 @@ export class IndividualVaultComponent implements OnInit, OnDestroy {
updateKeyModalRef: ViewContainerRef; updateKeyModalRef: ViewContainerRef;
favorites = false; favorites = false;
type: CipherType = null;
folderId: string = null; folderId: string = null;
collectionId: string = null; collectionId: string = null;
organizationId: string = null; organizationId: string = null;
@@ -208,7 +209,7 @@ export class IndividualVaultComponent implements OnInit, OnDestroy {
cipherPassesFilter = cipher.type === this.activeFilter.cipherType; cipherPassesFilter = cipher.type === this.activeFilter.cipherType;
} }
if ( if (
this.activeFilter.selectedFolder && this.activeFilter.selectedFolderId != null &&
this.activeFilter.selectedFolderId != "none" && this.activeFilter.selectedFolderId != "none" &&
cipherPassesFilter cipherPassesFilter
) { ) {
@@ -326,7 +327,7 @@ export class IndividualVaultComponent implements OnInit, OnDestroy {
async addCipher() { async addCipher() {
const component = await this.editCipher(null); const component = await this.editCipher(null);
component.type = this.activeFilter.cipherType; component.type = this.type;
component.folderId = this.folderId === "none" ? null : this.folderId; component.folderId = this.folderId === "none" ? null : this.folderId;
if (this.activeFilter.selectedCollectionId != null) { if (this.activeFilter.selectedCollectionId != null) {
const collection = this.filterComponent.collections.fullList.filter( const collection = this.filterComponent.collections.fullList.filter(
@@ -398,7 +399,7 @@ export class IndividualVaultComponent implements OnInit, OnDestroy {
if (queryParams == null) { if (queryParams == null) {
queryParams = { queryParams = {
favorites: this.favorites ? true : null, favorites: this.favorites ? true : null,
type: this.activeFilter.cipherType, type: this.type,
folderId: this.folderId, folderId: this.folderId,
collectionId: this.collectionId, collectionId: this.collectionId,
deleted: this.deleted ? true : null, deleted: this.deleted ? true : null,

View File

@@ -25,14 +25,13 @@ import { Organization } from "jslib-common/models/domain/organization";
import { CipherView } from "jslib-common/models/view/cipherView"; import { CipherView } from "jslib-common/models/view/cipherView";
import { EntityEventsComponent } from "../../../../organizations/manage/entity-events.component"; import { EntityEventsComponent } from "../../../../organizations/manage/entity-events.component";
import { AddEditComponent } from "../../../../organizations/vault/add-edit.component";
import { AttachmentsComponent } from "../../../../organizations/vault/attachments.component";
import { CiphersComponent } from "../../../../organizations/vault/ciphers.component";
import { CollectionsComponent } from "../../../../organizations/vault/collections.component";
import { VaultFilterComponent } from "../../../vault-filter/vault-filter.component"; import { VaultFilterComponent } from "../../../vault-filter/vault-filter.component";
import { VaultService } from "../../vault.service"; import { VaultService } from "../../vault.service";
import { AddEditComponent } from "./add-edit.component";
import { AttachmentsComponent } from "./attachments.component";
import { CiphersComponent } from "./ciphers.component";
import { CollectionsComponent } from "./collections.component";
const BroadcasterSubscriptionId = "OrgVaultComponent"; const BroadcasterSubscriptionId = "OrgVaultComponent";
@Component({ @Component({
@@ -173,7 +172,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy {
cipherPassesFilter = cipher.type === this.activeFilter.cipherType; cipherPassesFilter = cipher.type === this.activeFilter.cipherType;
} }
if ( if (
this.activeFilter.selectedFolder != null && this.activeFilter.selectedFolderId != null &&
this.activeFilter.selectedFolderId != "none" && this.activeFilter.selectedFolderId != "none" &&
cipherPassesFilter cipherPassesFilter
) { ) {

View File

@@ -2,22 +2,12 @@ import { NgModule } from "@angular/core";
import { VaultModule } from "../../vault.module"; import { VaultModule } from "../../vault.module";
import { AddEditComponent } from "./add-edit.component";
import { AttachmentsComponent } from "./attachments.component";
import { CiphersComponent } from "./ciphers.component";
import { CollectionsComponent } from "./collections.component";
import { OrganizationVaultRoutingModule } from "./organization-vault-routing.module"; import { OrganizationVaultRoutingModule } from "./organization-vault-routing.module";
import { OrganizationVaultComponent } from "./organization-vault.component"; import { OrganizationVaultComponent } from "./organization-vault.component";
@NgModule({ @NgModule({
imports: [VaultModule, OrganizationVaultRoutingModule], imports: [VaultModule, OrganizationVaultRoutingModule],
declarations: [ declarations: [OrganizationVaultComponent],
OrganizationVaultComponent,
AddEditComponent,
AttachmentsComponent,
CiphersComponent,
CollectionsComponent,
],
exports: [OrganizationVaultComponent], exports: [OrganizationVaultComponent],
}) })
export class OrganizationVaultModule {} export class OrganizationVaultModule {}

View File

@@ -1,5 +1,5 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router"; import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service"; import { OrganizationService } from "jslib-common/abstractions/organization.service";
@@ -17,7 +17,7 @@ export class PermissionsGuard implements CanActivate {
private syncService: SyncService private syncService: SyncService
) {} ) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { async canActivate(route: ActivatedRouteSnapshot) {
// TODO: We need to fix this issue once and for all. // TODO: We need to fix this issue once and for all.
if ((await this.syncService.getLastSync()) == null) { if ((await this.syncService.getLastSync()) == null) {
await this.syncService.fullSync(false); await this.syncService.fullSync(false);
@@ -39,16 +39,6 @@ export class PermissionsGuard implements CanActivate {
const permissions = route.data == null ? [] : (route.data.permissions as Permissions[]); const permissions = route.data == null ? [] : (route.data.permissions as Permissions[]);
if (permissions != null && !org.hasAnyPermission(permissions)) { if (permissions != null && !org.hasAnyPermission(permissions)) {
// Handle linkable ciphers for organizations the user only has view access to
// https://bitwarden.atlassian.net/browse/EC-203
if (state.root.queryParamMap.has("cipherId")) {
return this.router.createUrlTree(["/vault"], {
queryParams: {
cipherId: state.root.queryParamMap.get("cipherId"),
},
});
}
this.platformUtilsService.showToast("error", null, this.i18nService.t("accessDenied")); this.platformUtilsService.showToast("error", null, this.i18nService.t("accessDenied"));
return this.router.createUrlTree(["/"]); return this.router.createUrlTree(["/"]);
} }

View File

@@ -1,89 +0,0 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { Permissions } from "jslib-common/enums/permissions";
import { PermissionsGuard } from "../guards/permissions.guard";
import { PoliciesComponent } from "../policies/policies.component";
import { NavigationPermissionsService } from "../services/navigation-permissions.service";
import { CollectionsComponent } from "./collections.component";
import { EventsComponent } from "./events.component";
import { GroupsComponent } from "./groups.component";
import { ManageComponent } from "./manage.component";
import { PeopleComponent } from "./people.component";
const routes: Routes = [
{
path: "",
component: ManageComponent,
canActivate: [PermissionsGuard],
data: {
permissions: NavigationPermissionsService.getPermissions("manage"),
},
children: [
{
path: "",
pathMatch: "full",
redirectTo: "people",
},
{
path: "collections",
component: CollectionsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "collections",
permissions: [
Permissions.CreateNewCollections,
Permissions.EditAnyCollection,
Permissions.DeleteAnyCollection,
Permissions.EditAssignedCollections,
Permissions.DeleteAssignedCollections,
],
},
},
{
path: "events",
component: EventsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "eventLogs",
permissions: [Permissions.AccessEventLogs],
},
},
{
path: "groups",
component: GroupsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "groups",
permissions: [Permissions.ManageGroups],
},
},
{
path: "people",
component: PeopleComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "people",
permissions: [Permissions.ManageUsers, Permissions.ManageUsersPassword],
},
},
{
path: "policies",
component: PoliciesComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "policies",
permissions: [Permissions.ManagePolicies],
},
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ManageRoutingModule {}

View File

@@ -1,46 +0,0 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { SharedModule } from "../../modules/shared.module";
import { PoliciesModule } from "../policies/policies.module";
import { BulkConfirmComponent } from "./bulk/bulk-confirm.component";
import { BulkRemoveComponent } from "./bulk/bulk-remove.component";
import { BulkStatusComponent } from "./bulk/bulk-status.component";
import { CollectionAddEditComponent } from "./collection-add-edit.component";
import { CollectionsComponent as ManageCollectionsComponent } from "./collections.component";
import { EntityEventsComponent } from "./entity-events.component";
import { EventsComponent } from "./events.component";
import { GroupAddEditComponent } from "./group-add-edit.component";
import { GroupsComponent } from "./groups.component";
import { ManageRoutingModule } from "./manage-routing.module";
import { ManageComponent } from "./manage.component";
import { PeopleComponent } from "./people.component";
import { PolicyEditComponent } from "./policy-edit.component";
import { ResetPasswordComponent } from "./reset-password.component";
import { UserAddEditComponent } from "./user-add-edit.component";
import { UserConfirmComponent } from "./user-confirm.component";
import { UserGroupsComponent } from "./user-groups.component";
@NgModule({
imports: [CommonModule, SharedModule, PoliciesModule, ManageRoutingModule],
declarations: [
BulkConfirmComponent,
BulkRemoveComponent,
BulkStatusComponent,
CollectionAddEditComponent,
EntityEventsComponent,
EventsComponent,
GroupAddEditComponent,
GroupsComponent,
ManageCollectionsComponent,
ManageComponent,
PeopleComponent,
PolicyEditComponent,
ResetPasswordComponent,
UserAddEditComponent,
UserConfirmComponent,
UserGroupsComponent,
],
})
export class ManageModule {}

View File

@@ -10,9 +10,9 @@ import { Organization } from "jslib-common/models/domain/organization";
import { PolicyResponse } from "jslib-common/models/response/policyResponse"; import { PolicyResponse } from "jslib-common/models/response/policyResponse";
import { PolicyListService } from "../../services/policy-list.service"; import { PolicyListService } from "../../services/policy-list.service";
import { PolicyEditComponent } from "../manage/policy-edit.component"; import { BasePolicy } from "../policies/base-policy.component";
import { BasePolicy } from "./base-policy.component"; import { PolicyEditComponent } from "./policy-edit.component";
@Component({ @Component({
selector: "app-org-policies", selector: "app-org-policies",

View File

@@ -52,7 +52,7 @@
target="_blank" target="_blank"
rel="noopener" rel="noopener"
appA11yTitle="{{ 'learnMore' | i18n }}" appA11yTitle="{{ 'learnMore' | i18n }}"
href="https://bitwarden.com/help/user-types-access-control/" href="https://bitwarden.com/help/provider-users/"
> >
<i class="bwi bwi-question-circle" aria-hidden="true"></i> <i class="bwi bwi-question-circle" aria-hidden="true"></i>
</a> </a>

View File

@@ -0,0 +1,222 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { AuthGuard } from "jslib-angular/guards/auth.guard";
import { Permissions } from "jslib-common/enums/permissions";
import { PermissionsGuard } from "./guards/permissions.guard";
import { OrganizationLayoutComponent } from "./layouts/organization-layout.component";
import { CollectionsComponent } from "./manage/collections.component";
import { EventsComponent } from "./manage/events.component";
import { GroupsComponent } from "./manage/groups.component";
import { ManageComponent } from "./manage/manage.component";
import { PeopleComponent } from "./manage/people.component";
import { PoliciesComponent } from "./manage/policies.component";
import { NavigationPermissionsService } from "./services/navigation-permissions.service";
import { AccountComponent } from "./settings/account.component";
import { OrganizationBillingComponent } from "./settings/organization-billing.component";
import { OrganizationSubscriptionComponent } from "./settings/organization-subscription.component";
import { SettingsComponent } from "./settings/settings.component";
import { TwoFactorSetupComponent } from "./settings/two-factor-setup.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 { 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";
const routes: Routes = [
{
path: ":organizationId",
component: OrganizationLayoutComponent,
canActivate: [AuthGuard, PermissionsGuard],
data: {
permissions: NavigationPermissionsService.getPermissions("admin"),
},
children: [
{ path: "", pathMatch: "full", redirectTo: "vault" },
{
path: "vault",
loadChildren: async () =>
(await import("../modules/vault/modules/organization-vault/organization-vault.module"))
.OrganizationVaultModule,
},
{
path: "tools",
component: ToolsComponent,
canActivate: [PermissionsGuard],
data: { permissions: NavigationPermissionsService.getPermissions("tools") },
children: [
{
path: "",
pathMatch: "full",
redirectTo: "import",
},
{
path: "import",
component: ImportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "importData",
permissions: [Permissions.AccessImportExport],
},
},
{
path: "export",
component: ExportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "exportVault",
permissions: [Permissions.AccessImportExport],
},
},
{
path: "exposed-passwords-report",
component: ExposedPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "exposedPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "inactive-two-factor-report",
component: InactiveTwoFactorReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "inactive2faReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "reused-passwords-report",
component: ReusedPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "reusedPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "unsecured-websites-report",
component: UnsecuredWebsitesReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "unsecuredWebsitesReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "weak-passwords-report",
component: WeakPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "weakPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
],
},
{
path: "manage",
component: ManageComponent,
canActivate: [PermissionsGuard],
data: {
permissions: NavigationPermissionsService.getPermissions("manage"),
},
children: [
{
path: "",
pathMatch: "full",
redirectTo: "people",
},
{
path: "collections",
component: CollectionsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "collections",
permissions: [
Permissions.CreateNewCollections,
Permissions.EditAnyCollection,
Permissions.DeleteAnyCollection,
Permissions.EditAssignedCollections,
Permissions.DeleteAssignedCollections,
],
},
},
{
path: "events",
component: EventsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "eventLogs",
permissions: [Permissions.AccessEventLogs],
},
},
{
path: "groups",
component: GroupsComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "groups",
permissions: [Permissions.ManageGroups],
},
},
{
path: "people",
component: PeopleComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "people",
permissions: [Permissions.ManageUsers, Permissions.ManageUsersPassword],
},
},
{
path: "policies",
component: PoliciesComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "policies",
permissions: [Permissions.ManagePolicies],
},
},
],
},
{
path: "settings",
component: SettingsComponent,
canActivate: [PermissionsGuard],
data: { permissions: NavigationPermissionsService.getPermissions("settings") },
children: [
{ path: "", pathMatch: "full", redirectTo: "account" },
{ path: "account", component: AccountComponent, data: { titleId: "myOrganization" } },
{
path: "two-factor",
component: TwoFactorSetupComponent,
data: { titleId: "twoStepLogin" },
},
{
path: "billing",
component: OrganizationBillingComponent,
canActivate: [PermissionsGuard],
data: { titleId: "billing", permissions: [Permissions.ManageBilling] },
},
{
path: "subscription",
component: OrganizationSubscriptionComponent,
data: { titleId: "subscription" },
},
],
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class OrganizationsRoutingModule {}

View File

@@ -1,46 +0,0 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { AuthGuard } from "jslib-angular/guards/auth.guard";
import { PermissionsGuard } from "./guards/permissions.guard";
import { OrganizationLayoutComponent } from "./layouts/organization-layout.component";
import { NavigationPermissionsService } from "./services/navigation-permissions.service";
const routes: Routes = [
{
path: ":organizationId",
component: OrganizationLayoutComponent,
canActivate: [AuthGuard, PermissionsGuard],
data: {
permissions: NavigationPermissionsService.getPermissions("admin"),
},
children: [
{ path: "", pathMatch: "full", redirectTo: "vault" },
{
path: "vault",
loadChildren: async () =>
(await import("../modules/vault/modules/organization-vault/organization-vault.module"))
.OrganizationVaultModule,
},
{
path: "tools",
loadChildren: async () => (await import("./tools/tools.module")).ToolsModule,
},
{
path: "manage",
loadChildren: async () => (await import("./manage/manage.module")).ManageModule,
},
{
path: "settings",
loadChildren: async () => (await import("./settings/settings.module")).SettingsModule,
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class OrganizationsRoutingModule {}

View File

@@ -1,22 +0,0 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { LayoutsModule } from "../layouts/layouts.module";
import { SharedModule } from "../modules/shared.module";
import { OrganizationLayoutComponent } from "./layouts/organization-layout.component";
import { OrganizationSwitcherComponent } from "./layouts/organization-switcher.component";
import { OrganizationsRoutingModule } from "./organizations-routing.module";
import { AcceptFamilySponsorshipComponent } from "./sponsorships/accept-family-sponsorship.component";
import { FamiliesForEnterpriseSetupComponent } from "./sponsorships/families-for-enterprise-setup.component";
@NgModule({
imports: [CommonModule, OrganizationsRoutingModule, SharedModule, LayoutsModule],
declarations: [
AcceptFamilySponsorshipComponent,
FamiliesForEnterpriseSetupComponent,
OrganizationLayoutComponent,
OrganizationSwitcherComponent,
],
})
export class OrganizationsModule {}

View File

@@ -1,32 +0,0 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { SharedModule } from "../../modules/shared.module";
import { DisableSendPolicyComponent } from "./disable-send.component";
import { MasterPasswordPolicyComponent } from "./master-password.component";
import { PasswordGeneratorPolicyComponent } from "./password-generator.component";
import { PersonalOwnershipPolicyComponent } from "./personal-ownership.component";
import { PoliciesComponent } from "./policies.component";
import { RequireSsoPolicyComponent } from "./require-sso.component";
import { ResetPasswordPolicyComponent } from "./reset-password.component";
import { SendOptionsPolicyComponent } from "./send-options.component";
import { SingleOrgPolicyComponent } from "./single-org.component";
import { TwoFactorAuthenticationPolicyComponent } from "./two-factor-authentication.component";
@NgModule({
imports: [CommonModule, SharedModule],
declarations: [
DisableSendPolicyComponent,
MasterPasswordPolicyComponent,
PasswordGeneratorPolicyComponent,
PersonalOwnershipPolicyComponent,
RequireSsoPolicyComponent,
ResetPasswordPolicyComponent,
SendOptionsPolicyComponent,
SingleOrgPolicyComponent,
TwoFactorAuthenticationPolicyComponent,
PoliciesComponent,
],
})
export class PoliciesModule {}

View File

@@ -12,9 +12,9 @@ import { BillingResponse } from "jslib-common/models/response/billingResponse";
@Component({ @Component({
selector: "app-org-billing", selector: "app-org-billing",
templateUrl: "./billing.component.html", templateUrl: "./organization-billing.component.html",
}) })
export class BillingComponent implements OnInit { export class OrganizationBillingComponent implements OnInit {
loading = false; loading = false;
firstLoaded = false; firstLoaded = false;
showAdjustPayment = false; showAdjustPayment = false;

View File

@@ -23,9 +23,9 @@ import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
@Component({ @Component({
selector: "app-org-subscription", selector: "app-org-subscription",
templateUrl: "subscription.component.html", templateUrl: "organization-subscription.component.html",
}) })
export class SubscriptionComponent implements OnInit { export class OrganizationSubscriptionComponent implements OnInit {
@ViewChild("setupBillingSyncTemplate", { read: ViewContainerRef, static: true }) @ViewChild("setupBillingSyncTemplate", { read: ViewContainerRef, static: true })
setupBillingSyncModalRef: ViewContainerRef; setupBillingSyncModalRef: ViewContainerRef;

View File

@@ -1,48 +0,0 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { Permissions } from "jslib-common/enums/permissions";
import { PermissionsGuard } from "../guards/permissions.guard";
import { NavigationPermissionsService } from "../services/navigation-permissions.service";
import { AccountComponent } from "./account.component";
import { BillingComponent } from "./billing.component";
import { SettingsComponent } from "./settings.component";
import { SubscriptionComponent } from "./subscription.component";
import { TwoFactorSetupComponent } from "./two-factor-setup.component";
const routes: Routes = [
{
path: "",
component: SettingsComponent,
canActivate: [PermissionsGuard],
data: { permissions: NavigationPermissionsService.getPermissions("settings") },
children: [
{ path: "", pathMatch: "full", redirectTo: "account" },
{ path: "account", component: AccountComponent, data: { titleId: "myOrganization" } },
{
path: "two-factor",
component: TwoFactorSetupComponent,
data: { titleId: "twoStepLogin" },
},
{
path: "billing",
component: BillingComponent,
canActivate: [PermissionsGuard],
data: { titleId: "billing", permissions: [Permissions.ManageBilling] },
},
{
path: "subscription",
component: SubscriptionComponent,
data: { titleId: "subscription" },
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class SettingsRoutingModule {}

View File

@@ -1,35 +0,0 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { SharedModule } from "../../modules/shared.module";
import { AccountComponent } from "./account.component";
import { AdjustSubscription } from "./adjust-subscription.component";
import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component";
import { BillingComponent } from "./billing.component";
import { ChangePlanComponent } from "./change-plan.component";
import { DeleteOrganizationComponent } from "./delete-organization.component";
import { DownloadLicenseComponent } from "./download-license.component";
import { ImageSubscriptionHiddenComponent } from "./image-subscription-hidden.component";
import { SettingsRoutingModule } from "./settings-routing.module";
import { SettingsComponent } from "./settings.component";
import { SubscriptionComponent } from "./subscription.component";
import { TwoFactorSetupComponent } from "./two-factor-setup.component";
@NgModule({
imports: [CommonModule, SharedModule, SettingsRoutingModule],
declarations: [
AccountComponent,
AdjustSubscription,
BillingComponent,
BillingSyncApiKeyComponent,
ChangePlanComponent,
DeleteOrganizationComponent,
DownloadLicenseComponent,
ImageSubscriptionHiddenComponent,
SettingsComponent,
SubscriptionComponent,
TwoFactorSetupComponent,
],
})
export class SettingsModule {}

View File

@@ -1,101 +0,0 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { Permissions } from "jslib-common/enums/permissions";
import { PermissionsGuard } from "../guards/permissions.guard";
import { NavigationPermissionsService } from "../services/navigation-permissions.service";
import { ExportComponent } from "./export.component";
import { ExposedPasswordsReportComponent } from "./exposed-passwords-report.component";
import { ImportComponent } from "./import.component";
import { InactiveTwoFactorReportComponent } from "./inactive-two-factor-report.component";
import { ReusedPasswordsReportComponent } from "./reused-passwords-report.component";
import { ToolsComponent } from "./tools.component";
import { UnsecuredWebsitesReportComponent } from "./unsecured-websites-report.component";
import { WeakPasswordsReportComponent } from "./weak-passwords-report.component";
const routes: Routes = [
{
path: "",
component: ToolsComponent,
canActivate: [PermissionsGuard],
data: { permissions: NavigationPermissionsService.getPermissions("tools") },
children: [
{
path: "",
pathMatch: "full",
redirectTo: "import",
},
{
path: "import",
component: ImportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "importData",
permissions: [Permissions.AccessImportExport],
},
},
{
path: "export",
component: ExportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "exportVault",
permissions: [Permissions.AccessImportExport],
},
},
{
path: "exposed-passwords-report",
component: ExposedPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "exposedPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "inactive-two-factor-report",
component: InactiveTwoFactorReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "inactive2faReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "reused-passwords-report",
component: ReusedPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "reusedPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "unsecured-websites-report",
component: UnsecuredWebsitesReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "unsecuredWebsitesReport",
permissions: [Permissions.AccessReports],
},
},
{
path: "weak-passwords-report",
component: WeakPasswordsReportComponent,
canActivate: [PermissionsGuard],
data: {
titleId: "weakPasswordsReport",
permissions: [Permissions.AccessReports],
},
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ToolsRoutingModule {}

View File

@@ -1,29 +0,0 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { SharedModule } from "../../modules/shared.module";
import { ExportComponent } from "./export.component";
import { ExposedPasswordsReportComponent } from "./exposed-passwords-report.component";
import { ImportComponent } from "./import.component";
import { InactiveTwoFactorReportComponent } from "./inactive-two-factor-report.component";
import { ReusedPasswordsReportComponent } from "./reused-passwords-report.component";
import { ToolsRoutingModule } from "./tools-routing.module";
import { ToolsComponent } from "./tools.component";
import { UnsecuredWebsitesReportComponent } from "./unsecured-websites-report.component";
import { WeakPasswordsReportComponent } from "./weak-passwords-report.component";
@NgModule({
imports: [CommonModule, SharedModule, ToolsRoutingModule],
declarations: [
ExportComponent,
ExposedPasswordsReportComponent,
ImportComponent,
InactiveTwoFactorReportComponent,
ReusedPasswordsReportComponent,
ToolsComponent,
UnsecuredWebsitesReportComponent,
WeakPasswordsReportComponent,
],
})
export class ToolsModule {}

View File

@@ -22,11 +22,11 @@ import { Organization } from "jslib-common/models/domain/organization";
import { CipherCreateRequest } from "jslib-common/models/request/cipherCreateRequest"; import { CipherCreateRequest } from "jslib-common/models/request/cipherCreateRequest";
import { CipherRequest } from "jslib-common/models/request/cipherRequest"; import { CipherRequest } from "jslib-common/models/request/cipherRequest";
import { AddEditComponent as BaseAddEditComponent } from "../../../../vault/add-edit.component"; import { AddEditComponent as BaseAddEditComponent } from "../../vault/add-edit.component";
@Component({ @Component({
selector: "app-org-vault-add-edit", selector: "app-org-vault-add-edit",
templateUrl: "../../../../vault/add-edit.component.html", templateUrl: "../../vault/add-edit.component.html",
}) })
export class AddEditComponent extends BaseAddEditComponent { export class AddEditComponent extends BaseAddEditComponent {
organization: Organization; organization: Organization;

View File

@@ -12,11 +12,11 @@ import { Cipher } from "jslib-common/models/domain/cipher";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { AttachmentView } from "jslib-common/models/view/attachmentView"; import { AttachmentView } from "jslib-common/models/view/attachmentView";
import { AttachmentsComponent as BaseAttachmentsComponent } from "../../../../vault/attachments.component"; import { AttachmentsComponent as BaseAttachmentsComponent } from "../../vault/attachments.component";
@Component({ @Component({
selector: "app-org-vault-attachments", selector: "app-org-vault-attachments",
templateUrl: "../../../../vault/attachments.component.html", templateUrl: "../../vault/attachments.component.html",
}) })
export class AttachmentsComponent extends BaseAttachmentsComponent { export class AttachmentsComponent extends BaseAttachmentsComponent {
viewOnly = false; viewOnly = false;

View File

@@ -15,11 +15,11 @@ import { TotpService } from "jslib-common/abstractions/totp.service";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { CipherView } from "jslib-common/models/view/cipherView"; import { CipherView } from "jslib-common/models/view/cipherView";
import { CiphersComponent as BaseCiphersComponent } from "../../../../vault/ciphers.component"; import { CiphersComponent as BaseCiphersComponent } from "../../vault/ciphers.component";
@Component({ @Component({
selector: "app-org-vault-ciphers", selector: "app-org-vault-ciphers",
templateUrl: "../../../../vault/ciphers.component.html", templateUrl: "../../vault/ciphers.component.html",
}) })
export class CiphersComponent extends BaseCiphersComponent { export class CiphersComponent extends BaseCiphersComponent {
@Output() onEventsClicked = new EventEmitter<CipherView>(); @Output() onEventsClicked = new EventEmitter<CipherView>();

View File

@@ -11,11 +11,11 @@ import { Cipher } from "jslib-common/models/domain/cipher";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { CipherCollectionsRequest } from "jslib-common/models/request/cipherCollectionsRequest"; import { CipherCollectionsRequest } from "jslib-common/models/request/cipherCollectionsRequest";
import { CollectionsComponent as BaseCollectionsComponent } from "../../../../vault/collections.component"; import { CollectionsComponent as BaseCollectionsComponent } from "../../vault/collections.component";
@Component({ @Component({
selector: "app-org-vault-collections", selector: "app-org-vault-collections",
templateUrl: "../../../../vault/collections.component.html", templateUrl: "../../vault/collections.component.html",
}) })
export class CollectionsComponent extends BaseCollectionsComponent { export class CollectionsComponent extends BaseCollectionsComponent {
organization: Organization; organization: Organization;

View File

@@ -233,8 +233,10 @@ const routes: Routes = [
}, },
{ {
path: "organizations", path: "organizations",
loadChildren: async () => loadChildren: () =>
(await import("./organizations/organizations.module")).OrganizationsModule, import("./organizations/organization-routing.module").then(
(m) => m.OrganizationsRoutingModule
),
}, },
]; ];

View File

@@ -2,19 +2,19 @@ import { NgModule } from "@angular/core";
import { LooseComponentsModule } from "./modules/loose-components.module"; import { LooseComponentsModule } from "./modules/loose-components.module";
import { OrganizationManageModule } from "./modules/organizations/manage/organization-manage.module"; import { OrganizationManageModule } from "./modules/organizations/manage/organization-manage.module";
import { OrganizationUserModule } from "./modules/organizations/users/organization-user.module";
import { PipesModule } from "./modules/pipes/pipes.module"; import { PipesModule } from "./modules/pipes/pipes.module";
import { SharedModule } from "./modules/shared.module";
import { VaultFilterModule } from "./modules/vault-filter/vault-filter.module"; import { VaultFilterModule } from "./modules/vault-filter/vault-filter.module";
import { OrganizationBadgeModule } from "./modules/vault/modules/organization-badge/organization-badge.module"; import { OrganizationBadgeModule } from "./modules/vault/modules/organization-badge/organization-badge.module";
@NgModule({ @NgModule({
imports: [ imports: [
SharedModule,
LooseComponentsModule, LooseComponentsModule,
VaultFilterModule, VaultFilterModule,
OrganizationBadgeModule, OrganizationBadgeModule,
PipesModule, PipesModule,
OrganizationManageModule, OrganizationManageModule,
OrganizationUserModule,
], ],
exports: [LooseComponentsModule, VaultFilterModule, OrganizationBadgeModule, PipesModule], exports: [LooseComponentsModule, VaultFilterModule, OrganizationBadgeModule, PipesModule],
bootstrap: [], bootstrap: [],

View File

@@ -8,7 +8,7 @@ import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { Organization } from "jslib-common/models/domain/organization"; import { Organization } from "jslib-common/models/domain/organization";
import { CipherView } from "jslib-common/models/view/cipherView"; import { CipherView } from "jslib-common/models/view/cipherView";
import { AddEditComponent as OrgAddEditComponent } from "../modules/vault/modules/organization-vault/add-edit.component"; import { AddEditComponent as OrgAddEditComponent } from "../organizations/vault/add-edit.component";
import { AddEditComponent } from "../vault/add-edit.component"; import { AddEditComponent } from "../vault/add-edit.component";
@Directive() @Directive()

View File

@@ -1,7 +1,7 @@
<form #form (ngSubmit)="load()" [appApiAction]="formPromise" class="container" ngNativeValidate> <form #form (ngSubmit)="load()" [appApiAction]="formPromise" class="container" ngNativeValidate>
<div class="row justify-content-center mt-5"> <div class="row justify-content-center mt-5">
<div class="col-12"> <div class="col-12">
<h1 class="lead text-center mb-4">Bitwarden Send</h1> <p class="lead text-center mb-4">Bitwarden Send</p>
</div> </div>
<div class="col-12 text-center" *ngIf="creatorIdentifier != null"> <div class="col-12 text-center" *ngIf="creatorIdentifier != null">
<p>{{ "sendCreatorIdentifier" | i18n: creatorIdentifier }}</p> <p>{{ "sendCreatorIdentifier" | i18n: creatorIdentifier }}</p>

View File

@@ -307,9 +307,6 @@ export class EventService {
case EventType.Organization_DisabledKeyConnector: case EventType.Organization_DisabledKeyConnector:
msg = humanReadableMsg = this.i18nService.t("disabledKeyConnector"); msg = humanReadableMsg = this.i18nService.t("disabledKeyConnector");
break; break;
case EventType.Organization_SponsorshipsSynced:
msg = humanReadableMsg = this.i18nService.t("sponsorshipsSynced");
break;
// Policies // Policies
case EventType.Policy_Updated: { case EventType.Policy_Updated: {
msg = this.i18nService.t("modifiedPolicyId", this.formatPolicyId(ev)); msg = this.i18nService.t("modifiedPolicyId", this.formatPolicyId(ev));

View File

@@ -3,6 +3,7 @@ import { Component } from "@angular/core";
import { ApiService } from "jslib-common/abstractions/api.service"; import { ApiService } from "jslib-common/abstractions/api.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { OrganizationConnectionType } from "jslib-common/enums/organizationConnectionType"; import { OrganizationConnectionType } from "jslib-common/enums/organizationConnectionType";
import { Utils } from "jslib-common/misc/utils";
import { BillingSyncConfigApi } from "jslib-common/models/api/billingSyncConfigApi"; import { BillingSyncConfigApi } from "jslib-common/models/api/billingSyncConfigApi";
import { BillingSyncConfigRequest } from "jslib-common/models/request/billingSyncConfigRequest"; import { BillingSyncConfigRequest } from "jslib-common/models/request/billingSyncConfigRequest";
import { OrganizationConnectionRequest } from "jslib-common/models/request/organizationConnectionRequest"; import { OrganizationConnectionRequest } from "jslib-common/models/request/organizationConnectionRequest";

View File

@@ -40,13 +40,11 @@ export class GeneratorComponent extends BaseGeneratorComponent {
route, route,
window window
); );
if (platformUtilsService.isSelfHost()) { // Cannot use Firefox Relay on the web vault yet due to CORS issues with Firefox Relay API
// Cannot use Firefox Relay on self hosted web vaults due to CORS issues with Firefox Relay API this.forwardOptions.splice(
this.forwardOptions.splice( this.forwardOptions.findIndex((o) => o.value === "firefoxrelay"),
this.forwardOptions.findIndex((o) => o.value === "firefoxrelay"), 1
1 );
);
}
} }
async history() { async history() {

View File

@@ -4163,7 +4163,7 @@
"message": "Password reset success!" "message": "Password reset success!"
}, },
"resetPasswordEnrollmentWarning": { "resetPasswordEnrollmentWarning": {
"message": "Enrollment will allow organization administrators to change your master password" "message": "Enrollment will allow organization administrators to change your master password. Are you sure you want to enroll?"
}, },
"resetPasswordPolicy": { "resetPasswordPolicy": {
"message": "Master Password Reset" "message": "Master Password Reset"
@@ -4674,8 +4674,8 @@
"removeSponsorshipSuccess": { "removeSponsorshipSuccess": {
"message": "Sponsorship Removed" "message": "Sponsorship Removed"
}, },
"ssoKeyConnectorError": { "ssoKeyConnectorUnavailable": {
"message": "Key Connector error: make sure Key Connector is available and working correctly." "message": "Unable to reach the Key Connector, try again later."
}, },
"keyConnectorUrl": { "keyConnectorUrl": {
"message": "Key Connector URL" "message": "Key Connector URL"
@@ -5005,7 +5005,7 @@
"message": "Service" "message": "Service"
}, },
"unknownCipher": { "unknownCipher": {
"message": "Unknown Item, you may need to request permission to access this item." "message": "Unknown Item, you may need to login with another account to access this item."
}, },
"cannotSponsorSelf": { "cannotSponsorSelf": {
"message": "You cannot redeem for the active account. Enter a different email." "message": "You cannot redeem for the active account. Enter a different email."
@@ -5041,9 +5041,6 @@
"message": "Last Sync", "message": "Last Sync",
"Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\"" "Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\""
}, },
"sponsorshipsSynced": {
"message": "Self-hosted sponsorships synced."
},
"billingManagedByProvider": { "billingManagedByProvider": {
"message": "Managed by $PROVIDER$", "message": "Managed by $PROVIDER$",
"placeholders": { "placeholders": {

View File

@@ -14,6 +14,14 @@
font-size: $font-size-base; font-size: $font-size-base;
} }
a.create-organization-link {
&:hover {
@include themify($themes) {
color: themed("iconHover") !important;
}
}
}
button { button {
@extend .no-btn; @extend .no-btn;
} }