Skip to content

Commit

Permalink
feat: add batch denylist check (#166)
Browse files Browse the repository at this point in the history
Send an array of CID strings to check if they are on the denylist.
Response is the subset of the array that is on the denylist.

```http
POST /
Content-Type: application/json

["cid1","cid2"]
```

This will be used by e-ipfs to check a batch of cids at once, see:
elastic-ipfs/bitswap-peer#215

License: MIT

---------

Signed-off-by: Oli Evans <oli@protocol.ai>
  • Loading branch information
olizilla committed Jun 27, 2023
1 parent 1054a07 commit 407aecb
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
41 changes: 41 additions & 0 deletions packages/denylist/src/denylist.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,44 @@ export const denylistGet = async function (request, env) {
})
return response
}

/**
* Batch denylist check. POST an Array of cid strings.
* Returns the subset of the Array that are on the deny list.
* @param {Request} request
* @param {import('./env').Env} env
*/
export async function denylistPost (request, env) {
const contentType = request.headers.get('Content-Type')
if (contentType) {
const type = contentType.split(';').at(0)?.trim().toLowerCase()
if (type !== 'application/json') {
return new Response('Unsupported Media Type', { status: 415 })
}
}

let checklist
try {
checklist = await request.json()
} catch (err) {
return new Response('Invalid JSON', { status: 400, statusText: 'Bad Request' })
}

if (!Array.isArray(checklist)) {
return new Response('Expected an array', { status: 400, statusText: 'Bad Request' })
}

if (checklist.length > 1000) {
return new Response('Too many items. Max 1000', { status: 400, statusText: 'Bad Request' })
}

const body = []
for (const item of checklist) {
const res = await getFromDenyList(item, env)
if (res) {
body.push(item)
}
}

return new JSONResponse(body)
}
3 changes: 2 additions & 1 deletion packages/denylist/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Router } from 'itty-router'

import { denylistGet } from './denylist.js'
import { denylistGet, denylistPost } from './denylist.js'
import { versionGet } from './version.js'

import { addCorsHeaders, withCorsHeaders } from './cors.js'
Expand All @@ -19,6 +19,7 @@ router
.all('*', envAll)
.get('/version', withCorsHeaders(versionGet))
.get('/:cid', withCdnCache(withCorsHeaders(denylistGet)))
.post('/', withCorsHeaders(denylistPost))

/**
* @param {Error} error
Expand Down
49 changes: 49 additions & 0 deletions packages/denylist/test/denylist.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,52 @@ test('GET / caches response', async (t) => {
})
t.is(res2.status, 200)
})

test('POST / batch', async t => {
const { mf } = t.context
const cid = await createTestCid('CID CACHE TEST')
const denylistKv = await mf.getKVNamespace('DENYLIST')
await denylistKv.put(await toDenyListAnchor(cid), JSON.stringify({ status: 410, reason: 'blocked for testing the cache' }))

const checklist = ['QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq', cid]
let res = await mf.dispatchFetch('http://localhost:8787/', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(checklist)
})
t.is(res.status, 200)
const denylist = await res.json()
t.is(denylist.length, 1)
t.is(denylist[0], cid)

// not really cids, but we're checking that a max length limit is applied here
const tooLong = [...Array(1001).keys()]
res = await mf.dispatchFetch('http://localhost:8787/', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(tooLong)
})
t.is(res.status, 400)

res = await mf.dispatchFetch('http://localhost:8787/', {
method: 'POST',
headers: {
'content-type': 'application/JSON'
},
body: JSON.stringify(checklist).slice(0, -1)
})
t.is(res.status, 400)

res = await mf.dispatchFetch('http://localhost:8787/', {
method: 'POST',
headers: {
'content-type': 'application/jsonp'
},
body: JSON.stringify(checklist)
})
t.is(res.status, 415, 'should error when content-type not json')
})

0 comments on commit 407aecb

Please sign in to comment.