Skip to content

Commit d765918

Browse files
authored
fix(api-file-manager): security check on settings (#4626)
1 parent afb589a commit d765918

File tree

14 files changed

+103
-36
lines changed

14 files changed

+103
-36
lines changed
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { createHandler } from "@webiny/handler-aws/raw";
22
import elasticsearchClientContextPlugin from "@webiny/api-elasticsearch";
3-
import elasticsearchDataGzipCompression from "@webiny/api-elasticsearch/plugins/GzipCompression";
43
import { createEventHandler as createDynamoDBEventHandler } from "@webiny/api-dynamodb-to-elasticsearch";
54

65
export const handler = createHandler({
76
plugins: [
87
elasticsearchClientContextPlugin({
98
endpoint: `https://${process.env.ELASTIC_SEARCH_ENDPOINT}`
109
}),
11-
elasticsearchDataGzipCompression(),
1210
createDynamoDBEventHandler()
1311
]
1412
});

packages/api-file-manager/src/FileManagerContextSetup.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { FileManagerAliasesStorageOperations, FileManagerContext } from "~/types";
2-
import { createFileManager, FileManagerConfig } from "~/createFileManager";
1+
import {
2+
FileManagerAliasesStorageOperations,
3+
type FileManagerContext,
4+
FilePermission,
5+
type SettingsPermission
6+
} from "~/types";
7+
import type { FileManagerConfig } from "~/createFileManager/types";
8+
import { createFileManager } from "~/createFileManager";
39
import { FileStorage } from "~/storage/FileStorage";
410
import WebinyError from "@webiny/error";
511
import { SecurityPermission } from "@webiny/api-security/types";
@@ -8,6 +14,7 @@ import { CmsFilesStorage } from "~/cmsFileStorage/CmsFilesStorage";
814
import { CmsModelModifierPlugin } from "~/modelModifier/CmsModelModifier";
915
import { CmsModelPlugin, isHeadlessCmsReady } from "@webiny/api-headless-cms";
1016
import { FilesPermissions } from "~/createFileManager/permissions/FilesPermissions";
17+
import { SettingsPermissions } from "~/createFileManager/permissions/SettingsPermissions";
1118

1219
export class FileManagerContextSetup {
1320
private readonly context: FileManagerContext;
@@ -31,13 +38,21 @@ export class FileManagerContextSetup {
3138

3239
const filesPermissions = new FilesPermissions({
3340
getIdentity: this.context.security.getIdentity,
34-
getPermissions: () => this.context.security.getPermissions("fm.file"),
41+
getPermissions: () => this.context.security.getPermissions<FilePermission>("fm.file"),
42+
fullAccessPermissionName: "fm.*"
43+
});
44+
45+
const settingsPermissions = new SettingsPermissions({
46+
getIdentity: this.context.security.getIdentity,
47+
getPermissions: () =>
48+
this.context.security.getPermissions<SettingsPermission>("fm.settings"),
3549
fullAccessPermissionName: "fm.*"
3650
});
3751

3852
return createFileManager({
3953
storageOperations,
4054
filesPermissions,
55+
settingsPermissions,
4156
getTenantId: this.getTenantId.bind(this),
4257
getLocaleCode: this.getLocaleCode.bind(this),
4358
getIdentity: this.getIdentity.bind(this),

packages/api-file-manager/src/createFileManager/files.crud.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
import { NotFoundError } from "@webiny/handler-graphql";
22
import { createTopic } from "@webiny/pubsub";
33
import WebinyError from "@webiny/error";
4-
import {
4+
import type {
55
File,
66
FileManagerFilesStorageOperationsListParamsWhere,
77
FileManagerFilesStorageOperationsTagsParamsWhere,
88
FilesCRUD,
99
FilesListOpts
1010
} from "~/types";
11-
import { FileManagerConfig } from "~/createFileManager/index";
11+
import { FileManagerConfig } from "~/createFileManager/types";
1212
import { ROOT_FOLDER } from "~/contants";
1313
import { NotAuthorizedError } from "@webiny/api-security";
1414
import { getDate } from "@webiny/api-headless-cms/utils/date";
1515
import { getIdentity as utilsGetIdentity } from "@webiny/api-headless-cms/utils/identity";
1616
import { CmsEntryListSort } from "@webiny/api-headless-cms/types";
1717

18-
export const createFilesCrud = (config: FileManagerConfig): FilesCRUD => {
18+
export const createFilesCrud = (
19+
config: Pick<
20+
FileManagerConfig,
21+
| "storageOperations"
22+
| "filesPermissions"
23+
| "getLocaleCode"
24+
| "getTenantId"
25+
| "getIdentity"
26+
| "WEBINY_VERSION"
27+
>
28+
): FilesCRUD => {
1929
const {
2030
storageOperations,
2131
filesPermissions,

packages/api-file-manager/src/createFileManager/index.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
1-
import { FileManagerContextObject, FileManagerStorageOperations } from "~/types";
2-
import { GetPermissions, SecurityIdentity } from "@webiny/api-security/types";
1+
import type { FileManagerContextObject } from "~/types";
32
import { createFilesCrud } from "~/createFileManager/files.crud";
4-
import { FileStorage } from "~/storage/FileStorage";
53
import { createSettingsCrud } from "~/createFileManager/settings.crud";
64
import { createSystemCrud } from "~/createFileManager/system.crud";
7-
import { FilesPermissions } from "~/createFileManager/permissions/FilesPermissions";
8-
9-
export interface FileManagerConfig {
10-
storageOperations: FileManagerStorageOperations;
11-
filesPermissions: FilesPermissions;
12-
getTenantId: () => string;
13-
getLocaleCode: () => string;
14-
getIdentity: () => SecurityIdentity;
15-
getPermissions: GetPermissions;
16-
storage: FileStorage;
17-
WEBINY_VERSION: string;
18-
}
5+
import type { FileManagerConfig } from "~/createFileManager/types";
196

207
export const createFileManager = (config: FileManagerConfig): FileManagerContextObject => {
218
const filesCrud = createFilesCrud(config);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { AppPermissions } from "@webiny/api-security/utils/AppPermissions";
2+
import type { SettingsPermission } from "~/types";
3+
4+
export class SettingsPermissions extends AppPermissions<SettingsPermission> {}

packages/api-file-manager/src/createFileManager/settings.crud.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createTopic } from "@webiny/pubsub";
2-
import { FileManagerSettings, SettingsCRUD } from "~/types";
3-
import { FileManagerConfig } from "~/createFileManager/index";
2+
import type { FileManagerSettings, SettingsCRUD } from "~/types";
3+
import type { FileManagerConfig } from "./types";
44
import zod from "zod";
55
import { createZodError } from "@webiny/utils";
66

@@ -51,15 +51,21 @@ const updateDataModelValidation = zod.object({
5151

5252
export const createSettingsCrud = ({
5353
storageOperations,
54-
getTenantId
55-
}: FileManagerConfig): SettingsCRUD => {
54+
getTenantId,
55+
settingsPermissions
56+
}: Pick<
57+
FileManagerConfig,
58+
"storageOperations" | "getTenantId" | "settingsPermissions"
59+
>): SettingsCRUD => {
5660
return {
5761
onSettingsBeforeUpdate: createTopic("fileManager.onSettingsBeforeUpdate"),
5862
onSettingsAfterUpdate: createTopic("fileManager.onSettingsAfterUpdate"),
5963
async getSettings() {
6064
return storageOperations.settings.get({ tenant: getTenantId() });
6165
},
6266
async createSettings(data) {
67+
await settingsPermissions.ensure();
68+
6369
const results = createDataModelValidation.safeParse(data);
6470
if (!results.success) {
6571
throw createZodError(results.error);
@@ -73,6 +79,7 @@ export const createSettingsCrud = ({
7379
});
7480
},
7581
async updateSettings(data) {
82+
await settingsPermissions.ensure();
7683
const results = updateDataModelValidation.safeParse(data);
7784
if (!results.success) {
7885
throw createZodError(results.error);
@@ -118,6 +125,7 @@ export const createSettingsCrud = ({
118125
return result;
119126
},
120127
async deleteSettings() {
128+
await settingsPermissions.ensure();
121129
await storageOperations.settings.delete({ tenant: getTenantId() });
122130

123131
return true;

packages/api-file-manager/src/createFileManager/system.crud.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
import { createTopic } from "@webiny/pubsub";
22
import { NotAuthorizedError } from "@webiny/api-security";
3-
import {
3+
import type {
44
FileManagerContextObject,
55
FileManagerSettings,
66
FileManagerSystem,
77
SystemCRUD
88
} from "~/types";
99
import WebinyError from "@webiny/error";
10-
import { FileManagerConfig } from "~/createFileManager/index";
10+
import type { FileManagerConfig } from "~/createFileManager/types";
1111

1212
export const createSystemCrud = ({
1313
storageOperations,
1414
getTenantId,
1515
getIdentity,
1616
WEBINY_VERSION
17-
}: FileManagerConfig): SystemCRUD => {
17+
}: Pick<
18+
FileManagerConfig,
19+
"storageOperations" | "getTenantId" | "getIdentity" | "WEBINY_VERSION"
20+
>): SystemCRUD => {
1821
return {
1922
onSystemBeforeInstall: createTopic("fileManager.onSystemBeforeInstall"),
2023
onSystemAfterInstall: createTopic("fileManager.onSystemAfterInstall"),
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { FileManagerStorageOperations } from "~/types";
2+
import type { FilesPermissions } from "./permissions/FilesPermissions";
3+
import type { GetPermissions, SecurityIdentity } from "@webiny/api-security/types";
4+
import type { FileStorage } from "~/storage/FileStorage";
5+
import type { SettingsPermissions } from "./permissions/SettingsPermissions";
6+
7+
export interface FileManagerConfig {
8+
storageOperations: FileManagerStorageOperations;
9+
filesPermissions: FilesPermissions;
10+
settingsPermissions: SettingsPermissions;
11+
getTenantId: () => string;
12+
getLocaleCode: () => string;
13+
getIdentity: () => SecurityIdentity;
14+
getPermissions: GetPermissions;
15+
storage: FileStorage;
16+
WEBINY_VERSION: string;
17+
}

packages/api-file-manager/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { ContextPlugin } from "@webiny/api";
2-
import { FileManagerConfig } from "~/createFileManager";
3-
import { FileManagerContext } from "~/types";
2+
import type { FileManagerContext } from "~/types";
43
import { FileManagerContextSetup } from "./FileManagerContextSetup";
5-
import { setupAssetDelivery, AssetDeliveryParams } from "./delivery/setupAssetDelivery";
4+
import { AssetDeliveryParams, setupAssetDelivery } from "./delivery/setupAssetDelivery";
65
import { createGraphQLSchemaPlugin } from "./graphql";
76
import { applyThreatScanning } from "./enterprise/applyThreatScanning";
7+
import type { FileManagerConfig } from "./createFileManager/types";
88

99
export * from "./modelModifier/CmsModelModifier";
1010
export * from "./plugins";

packages/api-file-manager/src/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export interface FilePermission extends SecurityPermission {
3333
own?: boolean;
3434
}
3535

36+
export interface SettingsPermission extends SecurityPermission {
37+
name: "fm.setting";
38+
}
39+
3640
export interface FileInput {
3741
id: string;
3842

packages/api-page-builder/src/graphql/crud.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createPageElementsCrud } from "./crud/pageElements.crud";
99
import { createSettingsCrud } from "./crud/settings.crud";
1010
import { createSystemCrud } from "./crud/system.crud";
1111
import { ContextPlugin } from "@webiny/api";
12-
import { PbContext, PrerenderingHandlers } from "~/graphql/types";
12+
import { PbContext, PrerenderingHandlers, type SettingsSecurityPermission } from "~/graphql/types";
1313
import { createTopic } from "@webiny/pubsub";
1414
import { PageBuilderStorageOperations } from "~/types";
1515
import WebinyError from "@webiny/error";
@@ -21,6 +21,7 @@ import { PageTemplatesPermissions } from "~/graphql/crud/permissions/PageTemplat
2121
import { PageBlocksPermissions } from "~/graphql/crud/permissions/PageBlocksPermissions";
2222
import { GzipContentCompressionPlugin, JsonpackContentCompressionPlugin } from "~/plugins";
2323
import { createDataSourcesContext } from "~/dataSources/context/createDataSourcesContext";
24+
import { SettingsPermissions } from "~/graphql/crud/permissions/SettingsPermissions";
2425

2526
export interface CreateCrudParams {
2627
storageOperations: PageBuilderStorageOperations;
@@ -121,6 +122,13 @@ const setup = (params: CreateCrudParams) => {
121122
fullAccessPermissionName: "pb.*"
122123
});
123124

125+
const settingsPermissions = new SettingsPermissions({
126+
getIdentity: () => context.security.getIdentity(),
127+
getPermissions: () =>
128+
context.security.getPermissions<SettingsSecurityPermission>("pb.settings"),
129+
fullAccessPermissionName: "pb.*"
130+
});
131+
124132
const system = await createSystemCrud({
125133
context,
126134
storageOperations,
@@ -131,7 +139,8 @@ const setup = (params: CreateCrudParams) => {
131139
context,
132140
storageOperations,
133141
getTenantId,
134-
getLocaleCode
142+
getLocaleCode,
143+
settingsPermissions
135144
});
136145

137146
const menus = createMenuCrud({
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { AppPermissions } from "@webiny/api-security/utils/AppPermissions";
2+
import type { SettingsSecurityPermission } from "~/types";
3+
4+
export class SettingsPermissions extends AppPermissions<SettingsSecurityPermission> {}

packages/api-page-builder/src/graphql/crud/settings.crud.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import DataLoader from "dataloader";
1818
import { createTopic } from "@webiny/pubsub";
1919
import { createSettingsCreateValidation } from "~/graphql/crud/settings/validation";
2020
import { createZodError, removeUndefinedValues } from "@webiny/utils";
21+
import type { SettingsPermissions } from "./permissions/SettingsPermissions";
2122

2223
interface SettingsParams {
2324
tenant: string;
@@ -37,10 +38,11 @@ export interface CreateSettingsCrudParams {
3738
storageOperations: PageBuilderStorageOperations;
3839
getTenantId: () => string;
3940
getLocaleCode: () => string;
41+
settingsPermissions: SettingsPermissions;
4042
}
4143

4244
export const createSettingsCrud = (params: CreateSettingsCrudParams): SettingsCrud => {
43-
const { storageOperations, getLocaleCode, getTenantId } = params;
45+
const { storageOperations, getLocaleCode, getTenantId, settingsPermissions } = params;
4446

4547
const settingsDataLoader = new DataLoader<SettingsParams, Settings | null, string>(
4648
async keys => {
@@ -109,6 +111,8 @@ export const createSettingsCrud = (params: CreateSettingsCrudParams): SettingsCr
109111
},
110112

111113
async updateSettings(this: PageBuilderContextObject, input) {
114+
await settingsPermissions.ensure();
115+
112116
const params = {
113117
tenant: getTenantId(),
114118
locale: getLocaleCode(),

packages/api-page-builder/src/graphql/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,10 @@ export interface PageSecurityPermission extends PbSecurityPermission {
922922
pw: string;
923923
}
924924

925+
export interface SettingsSecurityPermission extends PbSecurityPermission {
926+
name: "pb.settings";
927+
}
928+
925929
// Page Builder lifecycle events.
926930
export interface PageBeforeRenderEvent extends Pick<RenderParams, "paths" | "tags"> {
927931
args: {

0 commit comments

Comments
 (0)