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:
1 parent
2be00007b2
commit
9a532de7bd
4 files changed
+66
-13
No files matched your search
@@ -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.canceled_by).not.toBeDefined()
|
||||||
expect(response.data.order_edit.confirmed_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", () => {
|
describe("POST /store/order-edits/:id/decline", () => {
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ export type QueryConfig<TEntity extends BaseEntity> = {
|
|||||||
defaultFields?: (keyof TEntity | string)[]
|
defaultFields?: (keyof TEntity | string)[]
|
||||||
defaultRelations?: string[]
|
defaultRelations?: string[]
|
||||||
allowedFields?: string[]
|
allowedFields?: string[]
|
||||||
|
allowedRelations?: string[]
|
||||||
defaultLimit?: number
|
defaultLimit?: number
|
||||||
isList?: boolean
|
isList?: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export const defaultOrderEditFields: (keyof OrderEdit)[] = [
|
|||||||
"internal_note",
|
"internal_note",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const storeOrderEditNotAllowedFields = [
|
export const storeOrderEditNotAllowedFieldsAndRelations = [
|
||||||
"internal_note",
|
"internal_note",
|
||||||
"created_by",
|
"created_by",
|
||||||
"confirmed_by",
|
"confirmed_by",
|
||||||
@@ -54,8 +54,8 @@ export const storeOrderEditNotAllowedFields = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const defaultStoreOrderEditRelations = defaultOrderEditRelations.filter(
|
export const defaultStoreOrderEditRelations = defaultOrderEditRelations.filter(
|
||||||
(field) => !storeOrderEditNotAllowedFields.includes(field)
|
(field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field)
|
||||||
)
|
)
|
||||||
export const defaultStoreOrderEditFields = defaultOrderEditFields.filter(
|
export const defaultStoreOrderEditFields = defaultOrderEditFields.filter(
|
||||||
(field) => !storeOrderEditNotAllowedFields.includes(field)
|
(field) => !storeOrderEditNotAllowedFieldsAndRelations.includes(field)
|
||||||
)
|
)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { pick } from "lodash"
|
import { pick } from "lodash"
|
||||||
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
|
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
|
||||||
import { MedusaError } from "medusa-core-utils/dist"
|
import { MedusaError } from "medusa-core-utils/dist"
|
||||||
import { BaseEntity } from "../interfaces/models/base-entity"
|
import { BaseEntity } from "../interfaces"
|
||||||
import { isDefined } from "."
|
import { isDefined } from "."
|
||||||
|
|
||||||
export function pickByConfig<TModel extends BaseEntity>(
|
export function pickByConfig<TModel extends BaseEntity>(
|
||||||
@@ -96,6 +96,14 @@ export function prepareListQuery<
|
|||||||
expandFields = fields.split(",") as (keyof TEntity)[]
|
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
|
let orderBy: { [k: symbol]: "DESC" | "ASC" } | undefined
|
||||||
if (isDefined(order)) {
|
if (isDefined(order)) {
|
||||||
let orderField = order
|
let orderField = order
|
||||||
@@ -145,15 +153,12 @@ export function prepareRetrieveQuery<
|
|||||||
expandFields = fields.split(",") as (keyof TEntity)[]
|
expandFields = fields.split(",") as (keyof TEntity)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryConfig?.allowedFields?.length) {
|
if (expandFields?.length && queryConfig?.allowedFields?.length) {
|
||||||
expandFields?.forEach((field) => {
|
validateFields(expandFields as string[], queryConfig.allowedFields)
|
||||||
if (!queryConfig?.allowedFields?.includes(field as string)) {
|
}
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
if (expandRelations?.length && queryConfig?.allowedRelations?.length) {
|
||||||
`Field ${field.toString()} is not valid`
|
validateRelations(expandRelations, queryConfig.allowedRelations)
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return getRetrieveConfig<TEntity>(
|
return getRetrieveConfig<TEntity>(
|
||||||
@@ -163,3 +168,38 @@ export function prepareRetrieveQuery<
|
|||||||
expandRelations
|
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`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user