feat(utils,types,framework,medusa): store endpoints should require publishable key (#9068)

* feat(utils,types,framework,medusa): store endpoints should require publishable key

* chore: fix specs

* chore: fix more specs

* chore: update js-sdk

* chore: fix specs wrt to default SC

* chore: revert custom headers + change error message

* chore: fix specs

* chore: fix new store specs
This commit is contained in:
Riqwan Thamir
2024-09-11 15:08:37 +02:00
committed by GitHub
parent fdd0543011
commit a729fb3fbb
29 changed files with 1037 additions and 464 deletions
+2
View File
@@ -48,6 +48,7 @@ import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
import { storeCollectionRoutesMiddlewares } from "./store/collections/middlewares"
import { storeCurrencyRoutesMiddlewares } from "./store/currencies/middlewares"
import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
import { storeRoutesMiddlewares } from "./store/middlewares"
import { storeOrderRoutesMiddlewares } from "./store/orders/middlewares"
import { storePaymentCollectionsMiddlewares } from "./store/payment-collections/middlewares"
import { storePaymentProvidersMiddlewares } from "./store/payment-providers/middlewares"
@@ -58,6 +59,7 @@ import { storeReturnReasonRoutesMiddlewares } from "./store/return-reasons/middl
import { storeShippingOptionRoutesMiddlewares } from "./store/shipping-options/middlewares"
export default defineMiddlewares([
...storeRoutesMiddlewares,
...adminCustomerGroupRoutesMiddlewares,
...adminCustomerRoutesMiddlewares,
...adminPromotionRoutesMiddlewares,
@@ -0,0 +1,10 @@
import { MiddlewareRoute } from "@medusajs/framework"
import { ensurePublishableApiKey } from "../../utils/middlewares/ensure-publishable-api-key"
export const storeRoutesMiddlewares: MiddlewareRoute[] = [
{
method: "ALL",
matcher: "/store*",
middlewares: [ensurePublishableApiKey()],
},
]
@@ -1,77 +1,49 @@
import { MedusaError } from "@medusajs/utils"
import { MedusaStoreRequest } from "@medusajs/framework"
import { arrayDifference, MedusaError } from "@medusajs/utils"
import { NextFunction } from "express"
import { AuthenticatedMedusaRequest } from "../../../../types/routing"
import { refetchEntity } from "../../refetch-entity"
import { arrayDifference } from "@medusajs/utils"
// Selection of sales channels happens in the following priority:
// - If a publishable API key is passed, we take the sales channels attached to it and filter them down based on the query params
// - If a sales channel id is passed through query params, we use that
// - If not, we use the default sales channel for the store
export function filterByValidSalesChannels() {
return async (req: AuthenticatedMedusaRequest, _, next: NextFunction) => {
const publishableApiKey = req.get("x-publishable-api-key")
const salesChannelIds = req.filterableFields.sales_channel_id as
| string[]
| undefined
return async (req: MedusaStoreRequest, _, next: NextFunction) => {
const idsFromRequest = req.filterableFields.sales_channel_id
const { sales_channel_ids: idsFromPublishableKey = [] } =
req.publishable_key_context
if (publishableApiKey) {
const apiKey = await refetchEntity(
"api_key",
{ token: publishableApiKey },
req.scope,
["id", "sales_channels_link.sales_channel_id"]
// If all sales channel ids are not in the publishable key, we throw an error
if (Array.isArray(idsFromRequest) && idsFromRequest.length) {
const uniqueInParams = arrayDifference(
idsFromRequest,
idsFromPublishableKey
)
if (!apiKey) {
if (uniqueInParams.length) {
return next(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Publishable API key not found`
`Requested sales channel is not part of the publishable key`
)
)
}
let result = apiKey.sales_channels_link.map(
(link) => link.sales_channel_id
)
if (salesChannelIds?.length) {
// If all sales channel ids are not in the publishable key, we throw an error
const uniqueInParams = arrayDifference(salesChannelIds, result)
if (uniqueInParams.length) {
return next(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested sales channel is not part of the publishable key mappings`
)
)
}
result = salesChannelIds
}
req.filterableFields.sales_channel_id = idsFromRequest
req.filterableFields.sales_channel_id = result
return next()
}
if (salesChannelIds?.length) {
req.filterableFields.sales_channel_id = salesChannelIds
if (idsFromPublishableKey?.length) {
req.filterableFields.sales_channel_id = idsFromPublishableKey
return next()
}
const store = await refetchEntity("stores", {}, req.scope, [
"default_sales_channel_id",
])
if (!store) {
return next(
new MedusaError(MedusaError.Types.INVALID_DATA, `Store not found`)
return next(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Publishable key needs to have a sales channel configured`
)
}
if (store.default_sales_channel_id) {
req.filterableFields.sales_channel_id = [store.default_sales_channel_id]
}
return next()
)
}
}