Fix(framework): http cors middleware order and options (#11765)
FIXES SUP-1101 also fixes https://github.com/medusajs/medusa/issues/11743 **What** The store cors is currently applied after the ensure publishable API key middleware, in this pr the order is fixed and the cors will be applied first.
This commit is contained in:
committed by
GitHub
parent
f00bb8efcf
commit
20cd59e622
5
.changeset/odd-cycles-destroy.md
Normal file
5
.changeset/odd-cycles-destroy.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/framework": patch
|
||||
---
|
||||
|
||||
Fix(framework): http cors middleware order and options
|
||||
@@ -0,0 +1,3 @@
|
||||
export function GET(req, res) {
|
||||
res.send("Hello from store custom route")
|
||||
}
|
||||
@@ -110,6 +110,7 @@ export const createServer = async (rootDir) => {
|
||||
`${url}${queryParams ? "?" + queryParams : ""}`
|
||||
)
|
||||
headers.Cookie = headers.Cookie || ""
|
||||
|
||||
if (opts.adminSession) {
|
||||
const token = generateJwtToken(
|
||||
{
|
||||
|
||||
@@ -46,12 +46,83 @@ describe("RoutesLoader", function () {
|
||||
})
|
||||
|
||||
expect(res.status).toBe(500)
|
||||
console.log(res)
|
||||
expect(res.text).toBe(
|
||||
'{"code":"unknown_error","type":"unknown_error","message":"An unknown error occurred."}'
|
||||
)
|
||||
})
|
||||
|
||||
it("should not succeed on cors preflight admin request failing", async function () {
|
||||
const res = await request("OPTIONS", "/admin/orders", {
|
||||
headers: {
|
||||
origin: "http://localhost:3000",
|
||||
"access-control-request-method": "GET",
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: "admin_user",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toBe(204)
|
||||
expect(res.headers["access-control-allow-origin"]).not.toBeTruthy()
|
||||
})
|
||||
|
||||
it("should not succeed on cors preflight store request failing", async function () {
|
||||
const res = await request("OPTIONS", "/store/custom", {
|
||||
headers: {
|
||||
origin: "http://localhost:3000",
|
||||
"access-control-request-method": "GET",
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: "admin_user",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toBe(204)
|
||||
expect(res.headers["access-control-allow-origin"]).not.toBeTruthy()
|
||||
})
|
||||
|
||||
it("should succeed on cors preflight admin request", async function () {
|
||||
const res = await request("OPTIONS", "/admin/orders", {
|
||||
headers: {
|
||||
origin: "http://localhost:7001",
|
||||
"access-control-request-method": "GET",
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: "admin_user",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toBe(204)
|
||||
expect(res.headers["access-control-allow-origin"]).toBe(
|
||||
"http://localhost:7001"
|
||||
)
|
||||
})
|
||||
|
||||
it("should succeed on cors preflight store request", async function () {
|
||||
const res = await request("OPTIONS", "/store/custom", {
|
||||
headers: {
|
||||
origin: "http://localhost:8000",
|
||||
"access-control-request-method": "GET",
|
||||
},
|
||||
adminSession: {
|
||||
jwt: {
|
||||
userId: "admin_user",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toBe(204)
|
||||
expect(res.headers["access-control-allow-origin"]).toBe(
|
||||
"http://localhost:8000"
|
||||
)
|
||||
})
|
||||
|
||||
it("should return a status 200 on GET admin/order/:id", async function () {
|
||||
const res = await request("GET", "/admin/orders/1000", {
|
||||
adminSession: {
|
||||
|
||||
@@ -201,6 +201,18 @@ describe("Routes loader", () => {
|
||||
"shouldAppendAuthCors": false,
|
||||
"shouldAppendStoreCors": false,
|
||||
},
|
||||
{
|
||||
"absolutePath": "${BASE_DIR}/store/custom/route.ts",
|
||||
"handler": [Function],
|
||||
"isRoute": true,
|
||||
"matcher": "/store/custom",
|
||||
"method": "GET",
|
||||
"optedOutOfAuth": false,
|
||||
"relativePath": "/store/custom/route.ts",
|
||||
"shouldAppendAdminCors": false,
|
||||
"shouldAppendAuthCors": false,
|
||||
"shouldAppendStoreCors": true,
|
||||
},
|
||||
]
|
||||
`)
|
||||
})
|
||||
@@ -409,6 +421,18 @@ describe("Routes loader", () => {
|
||||
"shouldAppendAuthCors": false,
|
||||
"shouldAppendStoreCors": false,
|
||||
},
|
||||
{
|
||||
"absolutePath": "${BASE_DIR}/store/custom/route.ts",
|
||||
"handler": [Function],
|
||||
"isRoute": true,
|
||||
"matcher": "/store/custom",
|
||||
"method": "GET",
|
||||
"optedOutOfAuth": false,
|
||||
"relativePath": "/store/custom/route.ts",
|
||||
"shouldAppendAdminCors": false,
|
||||
"shouldAppendAuthCors": false,
|
||||
"shouldAppendStoreCors": true,
|
||||
},
|
||||
{
|
||||
"absolutePath": "${BASE_DIR_2}/store/[customer_id]/orders/[order_id]/route.ts",
|
||||
"handler": [Function],
|
||||
|
||||
@@ -19,14 +19,11 @@ export async function ensurePublishableApiKeyMiddleware(
|
||||
const publishableApiKey = req.get(PUBLISHABLE_KEY_HEADER)
|
||||
|
||||
if (!isPresent(publishableApiKey)) {
|
||||
try {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`Publishable API key required in the request header: ${PUBLISHABLE_KEY_HEADER}. You can manage your keys in settings in the dashboard.`
|
||||
)
|
||||
} catch (e) {
|
||||
return next(e)
|
||||
}
|
||||
const error = new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`Publishable API key required in the request header: ${PUBLISHABLE_KEY_HEADER}. You can manage your keys in settings in the dashboard.`
|
||||
)
|
||||
return next(error)
|
||||
}
|
||||
|
||||
let apiKey
|
||||
|
||||
@@ -173,6 +173,7 @@ export class ApiLoader {
|
||||
return {
|
||||
origin: parseCorsOrigins(origin),
|
||||
credentials: true,
|
||||
preflightContinue: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,11 +195,13 @@ export class ApiLoader {
|
||||
res,
|
||||
next
|
||||
) {
|
||||
let method: string = req.method
|
||||
if (req.method === "OPTIONS") {
|
||||
method = req.headers["access-control-request-method"] ?? req.method
|
||||
}
|
||||
|
||||
const path = `${namespace}${req.path}`
|
||||
const matchingRoute = routesFinder.find(
|
||||
path,
|
||||
req.method as MiddlewareVerb
|
||||
)
|
||||
const matchingRoute = routesFinder.find(path, method as MiddlewareVerb)
|
||||
if (matchingRoute && matchingRoute[toggleKey] === true) {
|
||||
return corsFn(req, res, next)
|
||||
}
|
||||
@@ -213,7 +216,7 @@ export class ApiLoader {
|
||||
? (ApiLoader.traceMiddleware(corsMiddleware, {
|
||||
route: namespace,
|
||||
}) as RequestHandler)
|
||||
: cors(corsOptions)
|
||||
: corsMiddleware
|
||||
)
|
||||
}
|
||||
|
||||
@@ -334,16 +337,17 @@ export class ApiLoader {
|
||||
"api-key",
|
||||
])
|
||||
|
||||
/**
|
||||
* Publishable key check, CORS and auth setup for store routes.
|
||||
*/
|
||||
this.#applyStorePublishableKeyMiddleware("/store")
|
||||
this.#applyCorsMiddleware(
|
||||
routesFinder,
|
||||
"/store",
|
||||
"shouldAppendStoreCors",
|
||||
this.#createCorsOptions(configManager.config.projectConfig.http.storeCors)
|
||||
)
|
||||
/**
|
||||
* Publishable key check, CORS and auth setup for store routes.
|
||||
*/
|
||||
this.#applyStorePublishableKeyMiddleware("/store")
|
||||
|
||||
this.#applyAuthMiddleware(
|
||||
routesFinder,
|
||||
"/store",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { join, parse, sep } from "path"
|
||||
import { dynamicImport, readDirRecursive } from "@medusajs/utils"
|
||||
import { join, parse, sep } from "path"
|
||||
import { logger } from "../logger"
|
||||
import { type RouteVerb, HTTP_METHODS, type RouteDescriptor } from "./types"
|
||||
import { HTTP_METHODS, type RouteDescriptor, type RouteVerb } from "./types"
|
||||
|
||||
/**
|
||||
* File name that is used to indicate that the file is a route file
|
||||
|
||||
Reference in New Issue
Block a user