diff --git a/src/adapters/routes.ts b/src/adapters/routes.ts index 34d9245..75a1235 100644 --- a/src/adapters/routes.ts +++ b/src/adapters/routes.ts @@ -1,5 +1,6 @@ import { Router } from '@well-known-components/http-server' import * as authorizationMiddleware from 'decentraland-crypto-middleware' +import { withSignerValidation } from '../middlewares/withSignerValidation' import { GlobalContext } from '../types' import { createBidsHandler } from './handlers/bids' import { createOrdersHandler } from './handlers/orders' @@ -39,6 +40,7 @@ export async function setupRoutes(globalContext: GlobalContext) { optional: true, expiration: FIVE_MINUTES, }), + withSignerValidation, createNFTsHandler(components) ) router.get( @@ -47,6 +49,7 @@ export async function setupRoutes(globalContext: GlobalContext) { optional: true, expiration: FIVE_MINUTES, }), + withSignerValidation, createItemsHandler(components) ) router.get('/contracts', createContractsHandler(components)) @@ -71,6 +74,7 @@ export async function setupRoutes(globalContext: GlobalContext) { optional: true, expiration: FIVE_MINUTES, }), + withSignerValidation, createCatalogHandler(components) ) diff --git a/src/middlewares/withSignerValidation.ts b/src/middlewares/withSignerValidation.ts new file mode 100644 index 0000000..8bf2b61 --- /dev/null +++ b/src/middlewares/withSignerValidation.ts @@ -0,0 +1,20 @@ +import { IHttpServerComponent } from '@well-known-components/interfaces' + +export async function withSignerValidation( + ctx: IHttpServerComponent.DefaultContext, + next: () => Promise +): Promise { + if ( + ctx.verification && + ctx.verification.authMetadata && + typeof ctx.verification.authMetadata === 'object' && + ctx.verification.authMetadata.signer === 'decentraland-kernel-scene' + ) { + return { + status: 400, + body: 'Invalid signer', + } + } + + return await next() +} diff --git a/src/tests/middlewares/withSignerValidation.spec.ts b/src/tests/middlewares/withSignerValidation.spec.ts new file mode 100644 index 0000000..fd32e36 --- /dev/null +++ b/src/tests/middlewares/withSignerValidation.spec.ts @@ -0,0 +1,64 @@ +import { IHttpServerComponent } from "@well-known-components/interfaces" +import { withSignerValidation } from "../../middlewares/withSignerValidation" + +let ctx: IHttpServerComponent.DefaultContext + +describe("withSignerValidation", () => { + describe("when signer is decentraland-kernel-scene", () => { + beforeEach(() => { + ctx = { + verification: { + authMetadata: { + signer: "decentraland-kernel-scene", + }, + }, + } + }) + + it('should return 400 status and "Invalid signer" body', async () => { + const next = jest.fn() + const result = await withSignerValidation(ctx, next) + expect(result).toEqual({ + status: 400, + body: "Invalid signer", + }) + expect(next).not.toHaveBeenCalled() + }) + }) + + describe("when signer is not defined", () => { + beforeEach(() => { + ctx = { + verification: { + authMetadata: {}, + }, + } + }) + + it("should call next() and return its result", async () => { + const nextResult = { status: 200, body: "Success" } + const next = jest.fn().mockResolvedValue(nextResult) + const result = await withSignerValidation(ctx, next) + expect(result).toEqual(nextResult) + expect(next).toHaveBeenCalled() + }) + }) + + describe('when signer is not "decentraland-kernel-scene"', () => { + beforeEach(() => { + ctx = { + verification: { + authMetadata: { signer: "other-signer" }, + }, + } + }) + + it("should call next() and return its result", async () => { + const nextResult = { status: 200, body: "Success" } + const next = jest.fn().mockResolvedValue(nextResult) + const result = await withSignerValidation(ctx, next) + expect(result).toEqual(nextResult) + expect(next).toHaveBeenCalled() + }) + }) +})