mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
[PM-11360] Remove export permission for providers (#12062)
* Split organization.canAccessImportExport * Fix import permission to include CanCreateNewCollections * Remove provider export permission (feature flagged)
This commit is contained in:
@@ -27,7 +27,7 @@ export class ImportCommand {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!organization.canAccessImportExport) {
|
if (!organization.canAccessImport) {
|
||||||
return Response.badRequest(
|
return Response.badRequest(
|
||||||
"You are not authorized to import into the provided organization.",
|
"You are not authorized to import into the provided organization.",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -84,12 +84,12 @@
|
|||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
[text]="'importData' | i18n"
|
[text]="'importData' | i18n"
|
||||||
route="settings/tools/import"
|
route="settings/tools/import"
|
||||||
*ngIf="organization.canAccessImportExport"
|
*ngIf="organization.canAccessImport"
|
||||||
></bit-nav-item>
|
></bit-nav-item>
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
[text]="'exportVault' | i18n"
|
[text]="'exportVault' | i18n"
|
||||||
route="settings/tools/export"
|
route="settings/tools/export"
|
||||||
*ngIf="organization.canAccessImportExport"
|
*ngIf="canAccessExport$ | async"
|
||||||
></bit-nav-item>
|
></bit-nav-item>
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
[text]="'domainVerification' | i18n"
|
[text]="'domainVerification' | i18n"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ActivatedRoute, RouterModule } from "@angular/router";
|
import { ActivatedRoute, RouterModule } from "@angular/router";
|
||||||
import { combineLatest, map, mergeMap, Observable, Subject, switchMap, takeUntil } from "rxjs";
|
import { combineLatest, filter, map, Observable, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
import {
|
import {
|
||||||
@@ -12,7 +12,6 @@ import {
|
|||||||
canAccessReportingTab,
|
canAccessReportingTab,
|
||||||
canAccessSettingsTab,
|
canAccessSettingsTab,
|
||||||
canAccessVaultTab,
|
canAccessVaultTab,
|
||||||
getOrganizationById,
|
|
||||||
OrganizationService,
|
OrganizationService,
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
@@ -22,6 +21,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
|||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { getById } from "@bitwarden/common/platform/misc";
|
||||||
import { BannerModule, IconModule } from "@bitwarden/components";
|
import { BannerModule, IconModule } from "@bitwarden/components";
|
||||||
|
|
||||||
import { OrgSwitcherComponent } from "../../../layouts/org-switcher/org-switcher.component";
|
import { OrgSwitcherComponent } from "../../../layouts/org-switcher/org-switcher.component";
|
||||||
@@ -42,19 +42,18 @@ import { AdminConsoleLogo } from "../../icons/admin-console-logo";
|
|||||||
BannerModule,
|
BannerModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
export class OrganizationLayoutComponent implements OnInit {
|
||||||
protected readonly logo = AdminConsoleLogo;
|
protected readonly logo = AdminConsoleLogo;
|
||||||
|
|
||||||
protected orgFilter = (org: Organization) => canAccessOrgAdmin(org);
|
protected orgFilter = (org: Organization) => canAccessOrgAdmin(org);
|
||||||
|
|
||||||
organization$: Observable<Organization>;
|
organization$: Observable<Organization>;
|
||||||
|
canAccessExport$: Observable<boolean>;
|
||||||
showPaymentAndHistory$: Observable<boolean>;
|
showPaymentAndHistory$: Observable<boolean>;
|
||||||
hideNewOrgButton$: Observable<boolean>;
|
hideNewOrgButton$: Observable<boolean>;
|
||||||
organizationIsUnmanaged$: Observable<boolean>;
|
organizationIsUnmanaged$: Observable<boolean>;
|
||||||
isAccessIntelligenceFeatureEnabled = false;
|
isAccessIntelligenceFeatureEnabled = false;
|
||||||
|
|
||||||
private _destroy = new Subject<void>();
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
@@ -71,23 +70,23 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
|||||||
FeatureFlag.AccessIntelligence,
|
FeatureFlag.AccessIntelligence,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.organization$ = this.route.params
|
this.organization$ = this.route.params.pipe(
|
||||||
.pipe(takeUntil(this._destroy))
|
map((p) => p.organizationId),
|
||||||
.pipe<string>(map((p) => p.organizationId))
|
switchMap((id) => this.organizationService.organizations$.pipe(getById(id))),
|
||||||
.pipe(
|
filter((org) => org != null),
|
||||||
mergeMap((id) => {
|
);
|
||||||
return this.organizationService.organizations$
|
|
||||||
.pipe(takeUntil(this._destroy))
|
this.canAccessExport$ = combineLatest([
|
||||||
.pipe(getOrganizationById(id));
|
this.organization$,
|
||||||
}),
|
this.configService.getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission),
|
||||||
);
|
]).pipe(map(([org, removeProviderExport]) => org.canAccessExport(removeProviderExport)));
|
||||||
|
|
||||||
this.showPaymentAndHistory$ = this.organization$.pipe(
|
this.showPaymentAndHistory$ = this.organization$.pipe(
|
||||||
map(
|
map(
|
||||||
(org) =>
|
(org) =>
|
||||||
!this.platformUtilsService.isSelfHost() &&
|
!this.platformUtilsService.isSelfHost() &&
|
||||||
org?.canViewBillingHistory &&
|
org.canViewBillingHistory &&
|
||||||
org?.canEditPaymentMethods,
|
org.canEditPaymentMethods,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -107,11 +106,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this._destroy.next();
|
|
||||||
this._destroy.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
canShowVaultTab(organization: Organization): boolean {
|
canShowVaultTab(organization: Organization): boolean {
|
||||||
return canAccessVaultTab(organization);
|
return canAccessVaultTab(organization);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { inject, NgModule } from "@angular/core";
|
||||||
import { RouterModule, Routes } from "@angular/router";
|
import { CanMatchFn, RouterModule, Routes } from "@angular/router";
|
||||||
|
import { map } from "rxjs";
|
||||||
|
|
||||||
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
|
||||||
import { organizationPermissionsGuard } from "../../organizations/guards/org-permissions.guard";
|
import { organizationPermissionsGuard } from "../../organizations/guards/org-permissions.guard";
|
||||||
import { organizationRedirectGuard } from "../../organizations/guards/org-redirect.guard";
|
import { organizationRedirectGuard } from "../../organizations/guards/org-redirect.guard";
|
||||||
@@ -11,6 +14,11 @@ import { PoliciesComponent } from "../../organizations/policies";
|
|||||||
import { AccountComponent } from "./account.component";
|
import { AccountComponent } from "./account.component";
|
||||||
import { TwoFactorSetupComponent } from "./two-factor-setup.component";
|
import { TwoFactorSetupComponent } from "./two-factor-setup.component";
|
||||||
|
|
||||||
|
const removeProviderExportPermission$: CanMatchFn = () =>
|
||||||
|
inject(ConfigService)
|
||||||
|
.getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission)
|
||||||
|
.pipe(map((removeProviderExport) => removeProviderExport === true));
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
@@ -53,18 +61,32 @@ const routes: Routes = [
|
|||||||
path: "import",
|
path: "import",
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import("./org-import.component").then((mod) => mod.OrgImportComponent),
|
import("./org-import.component").then((mod) => mod.OrgImportComponent),
|
||||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)],
|
canActivate: [organizationPermissionsGuard((org) => org.canAccessImport)],
|
||||||
data: {
|
data: {
|
||||||
titleId: "importData",
|
titleId: "importData",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Export routing is temporarily duplicated to set the flag value passed into org.canAccessExport
|
||||||
|
{
|
||||||
|
path: "export",
|
||||||
|
loadComponent: () =>
|
||||||
|
import("../tools/vault-export/org-vault-export.component").then(
|
||||||
|
(mod) => mod.OrganizationVaultExportComponent,
|
||||||
|
),
|
||||||
|
canMatch: [removeProviderExportPermission$], // if this matches, the flag is ON
|
||||||
|
canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(true))],
|
||||||
|
data: {
|
||||||
|
titleId: "exportVault",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "export",
|
path: "export",
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import("../tools/vault-export/org-vault-export.component").then(
|
import("../tools/vault-export/org-vault-export.component").then(
|
||||||
(mod) => mod.OrganizationVaultExportComponent,
|
(mod) => mod.OrganizationVaultExportComponent,
|
||||||
),
|
),
|
||||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)],
|
canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(false))],
|
||||||
data: {
|
data: {
|
||||||
titleId: "exportVault",
|
titleId: "exportVault",
|
||||||
},
|
},
|
||||||
@@ -82,7 +104,7 @@ function getSettingsRoute(organization: Organization) {
|
|||||||
if (organization.canManagePolicies) {
|
if (organization.canManagePolicies) {
|
||||||
return "policies";
|
return "policies";
|
||||||
}
|
}
|
||||||
if (organization.canAccessImportExport) {
|
if (organization.canAccessImport) {
|
||||||
return ["tools", "import"];
|
return ["tools", "import"];
|
||||||
}
|
}
|
||||||
if (organization.canManageSso) {
|
if (organization.canManageSso) {
|
||||||
|
|||||||
@@ -152,7 +152,13 @@ export const SMAvailable: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: false, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: false,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [],
|
mockProviders: [],
|
||||||
},
|
},
|
||||||
@@ -162,7 +168,13 @@ export const SMAndACAvailable: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: true,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [],
|
mockProviders: [],
|
||||||
},
|
},
|
||||||
@@ -172,7 +184,13 @@ export const WithAllOptions: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: true,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [{ id: "provider-a" }] as Provider[],
|
mockProviders: [{ id: "provider-a" }] as Provider[],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -171,7 +171,13 @@ export const WithSM: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: false, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: false,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [],
|
mockProviders: [],
|
||||||
},
|
},
|
||||||
@@ -181,7 +187,13 @@ export const WithSMAndAC: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: true,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [],
|
mockProviders: [],
|
||||||
},
|
},
|
||||||
@@ -191,7 +203,13 @@ export const WithAllOptions: Story = {
|
|||||||
...Template,
|
...Template,
|
||||||
args: {
|
args: {
|
||||||
mockOrgs: [
|
mockOrgs: [
|
||||||
{ id: "org-a", canManageUsers: true, canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "org-a",
|
||||||
|
canManageUsers: true,
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => false,
|
||||||
|
},
|
||||||
] as Organization[],
|
] as Organization[],
|
||||||
mockProviders: [{ id: "provider-a" }] as Provider[],
|
mockProviders: [{ id: "provider-a" }] as Provider[],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,7 +110,12 @@ describe("ProductSwitcherService", () => {
|
|||||||
|
|
||||||
it("is included in bento when there is an organization with SM", async () => {
|
it("is included in bento when there is an organization with SM", async () => {
|
||||||
organizationService.organizations$ = of([
|
organizationService.organizations$ = of([
|
||||||
{ id: "1234", canAccessSecretsManager: true, enabled: true },
|
{
|
||||||
|
id: "1234",
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
canAccessExport: (_) => true,
|
||||||
|
},
|
||||||
] as Organization[]);
|
] as Organization[]);
|
||||||
|
|
||||||
initiateService();
|
initiateService();
|
||||||
@@ -220,8 +225,20 @@ describe("ProductSwitcherService", () => {
|
|||||||
router.url = "/sm/4243";
|
router.url = "/sm/4243";
|
||||||
|
|
||||||
organizationService.organizations$ = of([
|
organizationService.organizations$ = of([
|
||||||
{ id: "23443234", canAccessSecretsManager: true, enabled: true, name: "Org 2" },
|
{
|
||||||
{ id: "4243", canAccessSecretsManager: true, enabled: true, name: "Org 32" },
|
id: "23443234",
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
name: "Org 2",
|
||||||
|
canAccessExport: (_) => true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4243",
|
||||||
|
canAccessSecretsManager: true,
|
||||||
|
enabled: true,
|
||||||
|
name: "Org 32",
|
||||||
|
canAccessExport: (_) => true,
|
||||||
|
},
|
||||||
] as Organization[]);
|
] as Organization[]);
|
||||||
|
|
||||||
initiateService();
|
initiateService();
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { map, Observable } from "rxjs";
|
import { map, Observable } from "rxjs";
|
||||||
|
|
||||||
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
|
||||||
import { Utils } from "../../../platform/misc/utils";
|
|
||||||
import { UserId } from "../../../types/guid";
|
import { UserId } from "../../../types/guid";
|
||||||
import { OrganizationData } from "../../models/data/organization.data";
|
import { OrganizationData } from "../../models/data/organization.data";
|
||||||
import { Organization } from "../../models/domain/organization";
|
import { Organization } from "../../models/domain/organization";
|
||||||
@@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean {
|
|||||||
org.canManagePolicies ||
|
org.canManagePolicies ||
|
||||||
org.canManageSso ||
|
org.canManageSso ||
|
||||||
org.canManageScim ||
|
org.canManageScim ||
|
||||||
org.canAccessImportExport ||
|
org.canAccessImport ||
|
||||||
|
org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway
|
||||||
org.canManageDeviceApprovals
|
org.canManageDeviceApprovals
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -56,32 +55,6 @@ export function getOrganizationById(id: string) {
|
|||||||
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canAccessAdmin(i18nService: I18nService) {
|
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
|
||||||
orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
* To be removed after Flexible Collections.
|
|
||||||
**/
|
|
||||||
export function canAccessImportExport(i18nService: I18nService) {
|
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
|
||||||
orgs
|
|
||||||
.filter((org) => org.canAccessImportExport)
|
|
||||||
.sort(Utils.getSortFunction(i18nService, "name")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function canAccessImport(i18nService: I18nService) {
|
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
|
||||||
orgs
|
|
||||||
.filter((org) => org.canAccessImportExport || org.canCreateNewCollections)
|
|
||||||
.sort(Utils.getSortFunction(i18nService, "name")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `true` if a user is a member of an organization (rather than only being a ProviderUser)
|
* Returns `true` if a user is a member of an organization (rather than only being a ProviderUser)
|
||||||
* @deprecated Use organizationService.organizations$ with a filter instead
|
* @deprecated Use organizationService.organizations$ with a filter instead
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { map, Observable } from "rxjs";
|
import { map, Observable } from "rxjs";
|
||||||
|
|
||||||
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
|
||||||
import { Utils } from "../../../platform/misc/utils";
|
|
||||||
import { UserId } from "../../../types/guid";
|
import { UserId } from "../../../types/guid";
|
||||||
import { OrganizationData } from "../../models/data/organization.data";
|
import { OrganizationData } from "../../models/data/organization.data";
|
||||||
import { Organization } from "../../models/domain/organization";
|
import { Organization } from "../../models/domain/organization";
|
||||||
@@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean {
|
|||||||
org.canManagePolicies ||
|
org.canManagePolicies ||
|
||||||
org.canManageSso ||
|
org.canManageSso ||
|
||||||
org.canManageScim ||
|
org.canManageScim ||
|
||||||
org.canAccessImportExport ||
|
org.canAccessImport ||
|
||||||
|
org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway
|
||||||
org.canManageDeviceApprovals
|
org.canManageDeviceApprovals
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -56,20 +55,6 @@ export function getOrganizationById(id: string) {
|
|||||||
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
return map<Organization[], Organization | undefined>((orgs) => orgs.find((o) => o.id === id));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canAccessAdmin(i18nService: I18nService) {
|
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
|
||||||
orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function canAccessImport(i18nService: I18nService) {
|
|
||||||
return map<Organization[], Organization[]>((orgs) =>
|
|
||||||
orgs
|
|
||||||
.filter((org) => org.canAccessImportExport || org.canCreateNewCollections)
|
|
||||||
.sort(Utils.getSortFunction(i18nService, "name")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes an observable stream of organizations. This service is meant to
|
* Publishes an observable stream of organizations. This service is meant to
|
||||||
* be used widely across Bitwarden as the primary way of fetching organizations.
|
* be used widely across Bitwarden as the primary way of fetching organizations.
|
||||||
|
|||||||
@@ -168,8 +168,27 @@ export class Organization {
|
|||||||
return (this.isAdmin || this.permissions.accessEventLogs) && this.useEvents;
|
return (this.isAdmin || this.permissions.accessEventLogs) && this.useEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
get canAccessImportExport() {
|
get canAccessImport() {
|
||||||
return this.isAdmin || this.permissions.accessImportExport;
|
return (
|
||||||
|
this.isProviderUser ||
|
||||||
|
this.type === OrganizationUserType.Owner ||
|
||||||
|
this.type === OrganizationUserType.Admin ||
|
||||||
|
this.permissions.accessImportExport ||
|
||||||
|
this.canCreateNewCollections // To allow users to create collections and then import into them
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
canAccessExport(removeProviderExport: boolean) {
|
||||||
|
if (!removeProviderExport && this.isProviderUser) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.isMember &&
|
||||||
|
(this.type === OrganizationUserType.Owner ||
|
||||||
|
this.type === OrganizationUserType.Admin ||
|
||||||
|
this.permissions.accessImportExport)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get canAccessReports() {
|
get canAccessReports() {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export enum FeatureFlag {
|
|||||||
NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss",
|
NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss",
|
||||||
NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss",
|
NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss",
|
||||||
DisableFreeFamiliesSponsorship = "PM-12274-disable-free-families-sponsorship",
|
DisableFreeFamiliesSponsorship = "PM-12274-disable-free-families-sponsorship",
|
||||||
|
PM11360RemoveProviderExportPermission = "pm-11360-remove-provider-export-permission",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AllowedFeatureFlagTypes = boolean | number | string;
|
export type AllowedFeatureFlagTypes = boolean | number | string;
|
||||||
@@ -90,6 +91,7 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE,
|
[FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE,
|
||||||
[FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE,
|
[FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE,
|
||||||
[FeatureFlag.DisableFreeFamiliesSponsorship]: FALSE,
|
[FeatureFlag.DisableFreeFamiliesSponsorship]: FALSE,
|
||||||
|
[FeatureFlag.PM11360RemoveProviderExportPermission]: FALSE,
|
||||||
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
|
} satisfies Record<FeatureFlag, AllowedFeatureFlagTypes>;
|
||||||
|
|
||||||
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;
|
export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue;
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|||||||
import { safeProvider, SafeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
import { safeProvider, SafeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||||
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import {
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
canAccessImport,
|
|
||||||
OrganizationService,
|
|
||||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
@@ -226,7 +223,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
this.setImportOptions();
|
this.setImportOptions();
|
||||||
|
|
||||||
await this.initializeOrganizations();
|
await this.initializeOrganizations();
|
||||||
if (this.organizationId && (await this.canAccessImportExport(this.organizationId))) {
|
if (this.organizationId && (await this.canAccessImport(this.organizationId))) {
|
||||||
this.handleOrganizationImportInit();
|
this.handleOrganizationImportInit();
|
||||||
} else {
|
} else {
|
||||||
this.handleImportInit();
|
this.handleImportInit();
|
||||||
@@ -289,7 +286,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
private async initializeOrganizations() {
|
private async initializeOrganizations() {
|
||||||
this.organizations$ = concat(
|
this.organizations$ = concat(
|
||||||
this.organizationService.memberOrganizations$.pipe(
|
this.organizationService.memberOrganizations$.pipe(
|
||||||
canAccessImport(this.i18nService),
|
map((orgs) => orgs.filter((org) => org.canAccessImport)),
|
||||||
map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))),
|
map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -375,7 +372,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
importContents,
|
importContents,
|
||||||
this.organizationId,
|
this.organizationId,
|
||||||
this.formGroup.controls.targetSelector.value,
|
this.formGroup.controls.targetSelector.value,
|
||||||
(await this.canAccessImportExport(this.organizationId)) && this.isFromAC,
|
(await this.canAccessImport(this.organizationId)) && this.isFromAC,
|
||||||
);
|
);
|
||||||
|
|
||||||
//No errors, display success message
|
//No errors, display success message
|
||||||
@@ -395,11 +392,11 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async canAccessImportExport(organizationId?: string): Promise<boolean> {
|
private async canAccessImport(organizationId?: string): Promise<boolean> {
|
||||||
if (!organizationId) {
|
if (!organizationId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (await this.organizationService.get(this.organizationId))?.canAccessImportExport;
|
return (await this.organizationService.get(this.organizationId))?.canAccessImport;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormatInstructionTitle() {
|
getFormatInstructionTitle() {
|
||||||
|
|||||||
Reference in New Issue
Block a user