feat(medusa): Improve transform middleware (#2271)

**What**

Improve transform query middleware management of the allowed fields and relations in order to improve security upon access data

FIXES CORE-651
This commit is contained in:
Adrien de Peretti
2022-09-29 11:41:09 +02:00
committed by GitHub
parent 2be00007b2
commit 9a532de7bd
4 changed files with 66 additions and 13 deletions

View File

@@ -213,6 +213,18 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
expect(response.data.order_edit.canceled_by).not.toBeDefined()
expect(response.data.order_edit.confirmed_by).not.toBeDefined()
})
it("fails to get an order edit with disallowed fields query params", async () => {
const api = useApi()
const err = await api
.get(`/store/order-edits/${orderEditId}?fields=internal_note,order_id`)
.catch((e) => e)
expect(err.response.data.message).toBe(
"Fields [internal_note] are not valid"
)
})
})
describe("POST /store/order-edits/:id/decline", () => {

View File

@@ -91,6 +91,7 @@ export type QueryConfig<TEntity extends BaseEntity> = {
defaultFields?: (keyof TEntity | string)[]
defaultRelations?: string[]
allowedFields?: string[]
allowedRelations?: string[]
defaultLimit?: number
isList?: boolean
}

View File

@@ -46,7 +46,7 @@ export const defaultOrderEditFields: (keyof OrderEdit)[] = [
"internal_note",
]
export const storeOrderEditNotAllowedFields = [
export const storeOrderEditNotAllowedFieldsAndRelations = [
"internal_note",
"created_by",
"confirmed_by",
@@ -54,8 +54,8 @@ export const storeOrderEditNotAllowedFields = [
]
export const defaultStoreOrderEditRelations = defaultOrderEditRelations.filter(
(field) => !storeOrderEditNotAllowedFields.includes(field)
(field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field)
)
export const defaultStoreOrderEditFields = defaultOrderEditFields.filter(
(field) => !storeOrderEditNotAllowedFields.includes(field)
(field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field)
)

View File

@@ -1,7 +1,7 @@
import { pick } from "lodash"
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
import { MedusaError } from "medusa-core-utils/dist"
import { BaseEntity } from "../interfaces/models/base-entity"
import { BaseEntity } from "../interfaces"
import { isDefined } from "."
export function pickByConfig<TModel extends BaseEntity>(
@@ -96,6 +96,14 @@ export function prepareListQuery<
expandFields = fields.split(",") as (keyof TEntity)[]
}
if (expandFields?.length && queryConfig?.allowedFields?.length) {
validateFields(expandFields as string[], queryConfig.allowedFields)
}
if (expandRelations?.length && queryConfig?.allowedRelations?.length) {
validateRelations(expandRelations, queryConfig.allowedRelations)
}
let orderBy: { [k: symbol]: "DESC" | "ASC" } | undefined
if (isDefined(order)) {
let orderField = order
@@ -145,15 +153,12 @@ export function prepareRetrieveQuery<
expandFields = fields.split(",") as (keyof TEntity)[]
}
if (queryConfig?.allowedFields?.length) {
expandFields?.forEach((field) => {
if (!queryConfig?.allowedFields?.includes(field as string)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Field ${field.toString()} is not valid`
)
}
})
if (expandFields?.length && queryConfig?.allowedFields?.length) {
validateFields(expandFields as string[], queryConfig.allowedFields)
}
if (expandRelations?.length && queryConfig?.allowedRelations?.length) {
validateRelations(expandRelations, queryConfig.allowedRelations)
}
return getRetrieveConfig<TEntity>(
@@ -163,3 +168,38 @@ export function prepareRetrieveQuery<
expandRelations
)
}
function validateRelations(
relations: string[],
allowed: string[]
): void | never {
const disallowedRelationsFound: string[] = []
relations?.forEach((field) => {
if (!allowed.includes(field as string)) {
disallowedRelationsFound.push(field)
}
})
if (disallowedRelationsFound.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Relations [${disallowedRelationsFound.join(", ")}] are not valid`
)
}
}
function validateFields(fields: string[], allowed: string[]): void | never {
const disallowedFieldsFound: string[] = []
fields?.forEach((field) => {
if (!allowed.includes(field as string)) {
disallowedFieldsFound.push(field)
}
})
if (disallowedFieldsFound.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Fields [${disallowedFieldsFound.join(", ")}] are not valid`
)
}
}