fix(framework): Ensure that CORS and Auth middleware is applied for routes only defined in middlewares.ts (#10339)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/framework": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(framework): Apply CORS and auth middleware for global middleware that is not already applied by routes
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
"@mikro-orm/postgresql": "5.9.7",
|
"@mikro-orm/postgresql": "5.9.7",
|
||||||
"@swc/core": "^1.7.28",
|
"@swc/core": "^1.7.28",
|
||||||
"@swc/jest": "^0.2.36",
|
"@swc/jest": "^0.2.36",
|
||||||
|
"@types/cors": "^2.8.17",
|
||||||
"@types/jsonwebtoken": "^8.5.9",
|
"@types/jsonwebtoken": "^8.5.9",
|
||||||
"awilix": "^8.0.1",
|
"awilix": "^8.0.1",
|
||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
|
|||||||
@@ -183,6 +183,44 @@ function getBodyParserMiddleware(args?: ParserConfigArgs) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCorsOptions(origin: string): cors.CorsOptions {
|
||||||
|
return {
|
||||||
|
origin: parseCorsOrigins(origin),
|
||||||
|
credentials: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCors(
|
||||||
|
router: Router,
|
||||||
|
route: string | RegExp,
|
||||||
|
corsConfig: cors.CorsOptions
|
||||||
|
) {
|
||||||
|
router.use(route, cors(corsConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRouteContext(
|
||||||
|
path: string | RegExp
|
||||||
|
): "admin" | "store" | "auth" | null {
|
||||||
|
/**
|
||||||
|
* We cannot reliably guess the route context from a regex, so we skip it.
|
||||||
|
*/
|
||||||
|
if (path instanceof RegExp) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.startsWith("/admin")) {
|
||||||
|
return "admin"
|
||||||
|
}
|
||||||
|
if (path.startsWith("/store")) {
|
||||||
|
return "store"
|
||||||
|
}
|
||||||
|
if (path.startsWith("/auth")) {
|
||||||
|
return "auth"
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// TODO this router would need a proper rework, but it is out of scope right now
|
// TODO this router would need a proper rework, but it is out of scope right now
|
||||||
|
|
||||||
export class ApiRoutesLoader {
|
export class ApiRoutesLoader {
|
||||||
@@ -589,13 +627,15 @@ export class ApiRoutesLoader {
|
|||||||
/**
|
/**
|
||||||
* Applies middleware that checks if a valid publishable key is set on store request
|
* Applies middleware that checks if a valid publishable key is set on store request
|
||||||
*/
|
*/
|
||||||
applyStorePublishableKeyMiddleware(route: string) {
|
applyStorePublishableKeyMiddleware(route: string | RegExp) {
|
||||||
let middleware = ensurePublishableApiKeyMiddleware as unknown as
|
let middleware = ensurePublishableApiKeyMiddleware as unknown as
|
||||||
| RequestHandler
|
| RequestHandler
|
||||||
| MiddlewareFunction
|
| MiddlewareFunction
|
||||||
|
|
||||||
if (ApiRoutesLoader.traceMiddleware) {
|
if (ApiRoutesLoader.traceMiddleware) {
|
||||||
middleware = ApiRoutesLoader.traceMiddleware(middleware, { route: route })
|
middleware = ApiRoutesLoader.traceMiddleware(middleware, {
|
||||||
|
route: String(route),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#router.use(route, middleware as RequestHandler)
|
this.#router.use(route, middleware as RequestHandler)
|
||||||
@@ -606,7 +646,7 @@ export class ApiRoutesLoader {
|
|||||||
* needed to pass the middleware via the trace calls
|
* needed to pass the middleware via the trace calls
|
||||||
*/
|
*/
|
||||||
applyAuthMiddleware(
|
applyAuthMiddleware(
|
||||||
route: string,
|
route: string | RegExp,
|
||||||
actorType: string | string[],
|
actorType: string | string[],
|
||||||
authType: AuthType | AuthType[],
|
authType: AuthType | AuthType[],
|
||||||
options?: { allowUnauthenticated?: boolean; allowUnregistered?: boolean }
|
options?: { allowUnauthenticated?: boolean; allowUnregistered?: boolean }
|
||||||
@@ -617,7 +657,7 @@ export class ApiRoutesLoader {
|
|||||||
if (ApiRoutesLoader.traceMiddleware) {
|
if (ApiRoutesLoader.traceMiddleware) {
|
||||||
authenticateMiddleware = ApiRoutesLoader.traceMiddleware(
|
authenticateMiddleware = ApiRoutesLoader.traceMiddleware(
|
||||||
authenticateMiddleware,
|
authenticateMiddleware,
|
||||||
{ route: route }
|
{ route: String(route) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,6 +672,14 @@ export class ApiRoutesLoader {
|
|||||||
*/
|
*/
|
||||||
applyRouteSpecificMiddlewares(): void {
|
applyRouteSpecificMiddlewares(): void {
|
||||||
const prioritizedRoutes = prioritize([...this.#routesMap.values()])
|
const prioritizedRoutes = prioritize([...this.#routesMap.values()])
|
||||||
|
const handledPaths = new Set<string>()
|
||||||
|
const middlewarePaths = new Set<string | RegExp>()
|
||||||
|
|
||||||
|
const globalRoutes = this.#globalMiddlewaresDescriptor?.config?.routes ?? []
|
||||||
|
|
||||||
|
for (const route of globalRoutes) {
|
||||||
|
middlewarePaths.add(route.matcher)
|
||||||
|
}
|
||||||
|
|
||||||
for (const descriptor of prioritizedRoutes) {
|
for (const descriptor of prioritizedRoutes) {
|
||||||
if (!descriptor.config?.routes?.length) {
|
if (!descriptor.config?.routes?.length) {
|
||||||
@@ -639,58 +687,33 @@ export class ApiRoutesLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = descriptor.config
|
const config = descriptor.config
|
||||||
const routes = descriptor.config.routes
|
handledPaths.add(descriptor.route)
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply default store and admin middlewares if
|
|
||||||
* not opted out of.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (config.shouldAppendAdminCors) {
|
if (config.shouldAppendAdminCors) {
|
||||||
/**
|
applyCors(
|
||||||
* Apply the admin cors
|
this.#router,
|
||||||
*/
|
|
||||||
this.#router.use(
|
|
||||||
descriptor.route,
|
descriptor.route,
|
||||||
cors({
|
createCorsOptions(configManager.config.projectConfig.http.adminCors)
|
||||||
origin: parseCorsOrigins(
|
|
||||||
configManager.config.projectConfig.http.adminCors
|
|
||||||
),
|
|
||||||
credentials: true,
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.shouldAppendAuthCors) {
|
if (config.shouldAppendAuthCors) {
|
||||||
/**
|
applyCors(
|
||||||
* Apply the auth cors
|
this.#router,
|
||||||
*/
|
|
||||||
this.#router.use(
|
|
||||||
descriptor.route,
|
descriptor.route,
|
||||||
cors({
|
createCorsOptions(configManager.config.projectConfig.http.authCors)
|
||||||
origin: parseCorsOrigins(
|
|
||||||
configManager.config.projectConfig.http.authCors
|
|
||||||
),
|
|
||||||
credentials: true,
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.shouldAppendStoreCors) {
|
if (config.shouldAppendStoreCors) {
|
||||||
/**
|
applyCors(
|
||||||
* Apply the store cors
|
this.#router,
|
||||||
*/
|
|
||||||
this.#router.use(
|
|
||||||
descriptor.route,
|
descriptor.route,
|
||||||
cors({
|
createCorsOptions(configManager.config.projectConfig.http.storeCors)
|
||||||
origin: parseCorsOrigins(
|
|
||||||
configManager.config.projectConfig.http.storeCors
|
|
||||||
),
|
|
||||||
credentials: true,
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply other middlewares
|
||||||
if (config.routeType === "store") {
|
if (config.routeType === "store") {
|
||||||
this.applyStorePublishableKeyMiddleware(descriptor.route)
|
this.applyStorePublishableKeyMiddleware(descriptor.route)
|
||||||
}
|
}
|
||||||
@@ -715,7 +738,7 @@ export class ApiRoutesLoader {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of descriptor.config.routes) {
|
||||||
/**
|
/**
|
||||||
* Apply the body parser middleware if the route
|
* Apply the body parser middleware if the route
|
||||||
* has not opted out of it.
|
* has not opted out of it.
|
||||||
@@ -723,6 +746,51 @@ export class ApiRoutesLoader {
|
|||||||
this.applyBodyParserMiddleware(descriptor.route, route.method!)
|
this.applyBodyParserMiddleware(descriptor.route, route.method!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply CORS and auth middleware for paths defined in global middleware but not already handled by routes.
|
||||||
|
*/
|
||||||
|
for (const path of middlewarePaths) {
|
||||||
|
if (typeof path === "string" && handledPaths.has(path)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const context = getRouteContext(path)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (context) {
|
||||||
|
case "admin":
|
||||||
|
applyCors(
|
||||||
|
this.#router,
|
||||||
|
path,
|
||||||
|
createCorsOptions(configManager.config.projectConfig.http.adminCors)
|
||||||
|
)
|
||||||
|
this.applyAuthMiddleware(path, "user", [
|
||||||
|
"bearer",
|
||||||
|
"session",
|
||||||
|
"api-key",
|
||||||
|
])
|
||||||
|
break
|
||||||
|
case "store":
|
||||||
|
applyCors(
|
||||||
|
this.#router,
|
||||||
|
path,
|
||||||
|
createCorsOptions(configManager.config.projectConfig.http.storeCors)
|
||||||
|
)
|
||||||
|
this.applyStorePublishableKeyMiddleware(path)
|
||||||
|
break
|
||||||
|
case "auth":
|
||||||
|
applyCors(
|
||||||
|
this.#router,
|
||||||
|
path,
|
||||||
|
createCorsOptions(configManager.config.projectConfig.http.authCors)
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5754,6 +5754,7 @@ __metadata:
|
|||||||
"@opentelemetry/api": ^1.9.0
|
"@opentelemetry/api": ^1.9.0
|
||||||
"@swc/core": ^1.7.28
|
"@swc/core": ^1.7.28
|
||||||
"@swc/jest": ^0.2.36
|
"@swc/jest": ^0.2.36
|
||||||
|
"@types/cors": ^2.8.17
|
||||||
"@types/express": ^4.17.17
|
"@types/express": ^4.17.17
|
||||||
"@types/jsonwebtoken": ^8.5.9
|
"@types/jsonwebtoken": ^8.5.9
|
||||||
awilix: ^8.0.1
|
awilix: ^8.0.1
|
||||||
@@ -13414,6 +13415,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/cors@npm:^2.8.17":
|
||||||
|
version: 2.8.17
|
||||||
|
resolution: "@types/cors@npm:2.8.17"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "*"
|
||||||
|
checksum: 457364c28c89f3d9ed34800e1de5c6eaaf344d1bb39af122f013322a50bc606eb2aa6f63de4e41a7a08ba7ef454473926c94a830636723da45bf786df032696d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/doctrine@npm:^0.0.9":
|
"@types/doctrine@npm:^0.0.9":
|
||||||
version: 0.0.9
|
version: 0.0.9
|
||||||
resolution: "@types/doctrine@npm:0.0.9"
|
resolution: "@types/doctrine@npm:0.0.9"
|
||||||
|
|||||||
Reference in New Issue
Block a user