Skip to content

Commit

Permalink
feat: add signer check middleware (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
marianogoldman authored Jun 17, 2024
1 parent b537829 commit 0f071b9
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 60 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@dcl/catalyst-storage": "^4.2.0",
"@dcl/crypto": "^3.4.5",
"@dcl/hashing": "^3.0.4",
"@dcl/platform-crypto-middleware": "^1.0.2",
"@dcl/platform-crypto-middleware": "^1.1.0",
"@dcl/platform-server-commons": "^0.0.4",
"@dcl/schemas": "^11.9.1",
"@ensdomains/eth-ens-namehash": "^2.0.15",
Expand Down
25 changes: 3 additions & 22 deletions src/controllers/handlers/cast-adapter-handler.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { HandlerContextWithPath } from '../../types'
import { IHttpServerComponent } from '@well-known-components/interfaces'
import { DecentralandSignatureContext, verify } from '@dcl/platform-crypto-middleware'
import { DecentralandSignatureContext } from '@dcl/platform-crypto-middleware'
import { AccessToken } from 'livekit-server-sdk'
import { assertNotBlockedOrWithinInGracePeriod } from '../../logic/blocked'
import { InvalidRequestError, NotFoundError } from '@dcl/platform-server-commons'

export async function castAdapterHandler(
context: HandlerContextWithPath<
'config' | 'fetch' | 'nameDenyListChecker' | 'namePermissionChecker' | 'storage' | 'worldsManager',
'config' | 'nameDenyListChecker' | 'namePermissionChecker' | 'storage' | 'worldsManager',
'/meet-adapter/:roomId'
> &
DecentralandSignatureContext<any>
): Promise<IHttpServerComponent.IResponse> {
const {
components: { config, fetch, nameDenyListChecker, namePermissionChecker, worldsManager }
components: { config, nameDenyListChecker, namePermissionChecker, worldsManager }
} = context

const [host, apiKey, apiSecret] = await Promise.all([
Expand All @@ -22,25 +22,6 @@ export async function castAdapterHandler(
config.requireString('LIVEKIT_API_SECRET')
])

const baseUrl = (
(await config.getString('HTTP_BASE_URL')) || `${context.url.protocol}//${context.url.host}`
).toString()
const path = new URL(baseUrl + context.url.pathname)

try {
context.verification = await verify(context.request.method, path.pathname, context.request.headers.raw(), {
fetcher: fetch
})
} catch (e) {
return {
status: 401,
body: {
ok: false,
message: 'Access denied, invalid signed-fetch request'
}
}
}

if (!validateMetadata(context.verification!.authMetadata)) {
throw new InvalidRequestError('Access denied, invalid metadata')
}
Expand Down
24 changes: 3 additions & 21 deletions src/controllers/handlers/comms-adapter-handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HandlerContextWithPath } from '../../types'
import { IHttpServerComponent } from '@well-known-components/interfaces'
import { verify, DecentralandSignatureContext } from '@dcl/platform-crypto-middleware'
import { DecentralandSignatureContext } from '@dcl/platform-crypto-middleware'
import { assertNotBlockedOrWithinInGracePeriod } from '../../logic/blocked'
import { InvalidRequestError, NotAuthorizedError, NotFoundError } from '@dcl/platform-server-commons'

Expand All @@ -10,33 +10,15 @@ type CommsMetadata = {

export async function commsAdapterHandler(
context: HandlerContextWithPath<
'commsAdapter' | 'fetch' | 'config' | 'nameDenyListChecker' | 'namePermissionChecker' | 'worldsManager',
'commsAdapter' | 'config' | 'nameDenyListChecker' | 'namePermissionChecker' | 'worldsManager',
'/get-comms-adapter/:roomId'
> &
DecentralandSignatureContext<CommsMetadata>
): Promise<IHttpServerComponent.IResponse> {
const {
components: { commsAdapter, config, fetch, nameDenyListChecker, namePermissionChecker, worldsManager }
components: { commsAdapter, config, nameDenyListChecker, namePermissionChecker, worldsManager }
} = context

const baseUrl = (await config.getString('HTTP_BASE_URL')) || `${context.url.protocol}//${context.url.host}`

const path = new URL(baseUrl + context.url.pathname)

try {
context.verification = await verify(context.request.method, path.pathname, context.request.headers.raw(), {
fetcher: fetch
})
} catch (e) {
return {
status: 401,
body: {
ok: false,
message: 'Access denied, invalid signed-fetch request'
}
}
}

const authMetadata = context.verification!.authMetadata
if (!validateMetadata(authMetadata)) {
throw new InvalidRequestError('Access denied, invalid metadata')
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/handlers/undeploy-entity-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IHttpServerComponent } from '@well-known-components/interfaces'
import { HandlerContextWithPath } from '../../types'
import { DecentralandSignatureContext } from '@dcl/platform-crypto-middleware'
import { InvalidRequestError } from '@dcl/platform-server-commons'
import { DecentralandSignatureContext } from '@dcl/platform-crypto-middleware'

export async function undeployEntity({
params,
Expand Down
10 changes: 7 additions & 3 deletions src/controllers/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ export async function setupRouter(globalContext: GlobalContext): Promise<Router<
const signedFetchMiddleware = wellKnownComponents({
fetcher: globalContext.components.fetch,
optional: false,
onError: (err) => ({ error: err.message, message: 'This endpoint requires a signed fetch request. See ADR-44.' })
metadataValidator: (metadata: Record<string, any>): boolean => metadata.signer !== 'decentraland-kernel-scene',
onError: (err: any) => ({
error: err.message,
message: 'This endpoint requires a signed fetch request. See ADR-44.'
})
})

router.get('/world/:world_name/about', worldAboutHandler)
Expand Down Expand Up @@ -70,8 +74,8 @@ export async function setupRouter(globalContext: GlobalContext): Promise<Router<
router.get('/index', getIndexHandler)
router.get('/live-data', getLiveDataHandler)

router.post('/get-comms-adapter/:roomId', commsAdapterHandler)
router.post('/cast-adapter/:roomId', castAdapterHandler)
router.post('/get-comms-adapter/:roomId', signedFetchMiddleware, commsAdapterHandler)
router.post('/cast-adapter/:roomId', signedFetchMiddleware, castAdapterHandler)

// administrative endpoints
const secret = await globalContext.components.config.requireString('AUTH_SECRET')
Expand Down
6 changes: 3 additions & 3 deletions test/integration/cast-adapter-handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ test('cast adapter handler /cast-adapter/:roomId', function ({ components, stubC
method: 'POST'
})

expect(r.status).toEqual(401)
expect(r.status).toEqual(400)
expect(await r.json()).toEqual({
message: 'Access denied, invalid signed-fetch request',
ok: false
error: 'Invalid Auth Chain',
message: 'This endpoint requires a signed fetch request. See ADR-44.'
})
})
})
6 changes: 3 additions & 3 deletions test/integration/comms-adapter-handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ test('comms adapter handler /get-comms-adapter/:roomId', function ({ components,
method: 'POST'
})

expect(r.status).toEqual(401)
expect(r.status).toEqual(400)
expect(await r.json()).toEqual({
message: 'Access denied, invalid signed-fetch request',
ok: false
error: 'Invalid Auth Chain',
message: 'This endpoint requires a signed fetch request. See ADR-44.'
})
})
})
21 changes: 19 additions & 2 deletions test/integration/undeploy-entity-handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { getAuthHeaders, getIdentity, Identity } from '../utils'
import { Authenticator } from '@dcl/crypto'

test('undeploy entity handler /entities/:world_name', function ({ components, stubComponents }) {
function makeRequest(path: string, identity: Identity) {
function makeRequest(path: string, identity: Identity, metadata: Record<string, any> = {}) {
const { localFetch } = components

return localFetch.fetch(path, {
method: 'DELETE',
headers: {
...getAuthHeaders('DELETE', path, {}, (payload) =>
...getAuthHeaders('DELETE', path, metadata, (payload) =>
Authenticator.signPayload(
{
ephemeralIdentity: identity.ephemeralIdentity,
Expand All @@ -36,6 +36,23 @@ test('undeploy entity handler /entities/:world_name', function ({ components, st
expect(await r.json()).toMatchObject({ message: 'Invalid request. You have no permission to undeploy the scene.' })
})

it('cannot undeploy if signer is sdk', async () => {
const { worldCreator } = components

const identity = await getIdentity()

const { worldName } = await worldCreator.createWorldWithScene({
owner: identity.authChain
})

const r = await makeRequest(`/entities/${worldName}`, identity, {
signer: 'decentraland-kernel-scene'
})

expect(r.status).toEqual(400)
expect(await r.json()).toMatchObject({ message: 'This endpoint requires a signed fetch request. See ADR-44.' })
})

it('successfully un-deploys a world', async () => {
const { worldCreator } = components
const { namePermissionChecker } = stubComponents
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -795,10 +795,10 @@
resolved "https://registry.yarnpkg.com/@dcl/hashing/-/hashing-3.0.4.tgz#4df2a4cb3a8114765aed34cb57b91c93bf33bfb3"
integrity sha512-Cg+MoIOn+BYmQV2q8zSFnNYY+GldlnUazwBnfgrq3i66ZxOaZ65h01btd8OUtSAlfWG4VTNIOHDjtKqmuwJNBg==

"@dcl/platform-crypto-middleware@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@dcl/platform-crypto-middleware/-/platform-crypto-middleware-1.0.2.tgz#3daf9af7f04bd95f833dcf2c421171b37ea1bea6"
integrity sha512-V99zV5XntoXmZclSj5t4S8Ioi0s7jULep7dw1UmpvnXDvozQjUNX9w5sWnXrcAalTocXHbf7bL7xK6sHHDZ0Mw==
"@dcl/platform-crypto-middleware@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@dcl/platform-crypto-middleware/-/platform-crypto-middleware-1.1.0.tgz#11434eb4fc8d461799ab71d28ce869ab330bdb23"
integrity sha512-E2AAIRcbeF+DLQ6urmOkoqwSOGaBlX498nygyOc3EnChEPjJhM0LiTQ9rwAG572DdMGf8ZGbNg+odx6i9M3cMA==
dependencies:
"@dcl/crypto" "^3.4.3"
"@well-known-components/fetch-component" "^2.0.2"
Expand Down

0 comments on commit 0f071b9

Please sign in to comment.