Skip to content

Commit

Permalink
Add csp and nosniff when serving user uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
devinivy committed Apr 29, 2023
1 parent 01b5971 commit 3d1b3b3
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 8 deletions.
2 changes: 2 additions & 0 deletions packages/bsky/src/api/blob-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ export const createRouter = (ctx: AppContext): express.Router => {
// closing chunk) if the bytes don't match the expected cid.
res.statusCode = 200
res.setHeader('content-type', verifiedImage.contentType)
res.setHeader('x-content-type-options', 'nosniff')
res.setHeader('content-security-policy', `default-src 'none'; sandbox`)
pipeline(verifiedImage.stream, res, (err) => {
if (err) {
log.warn(
Expand Down
7 changes: 6 additions & 1 deletion packages/bsky/tests/blob-resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ describe('blob resolver', () => {
})

it('resolves blob with good signature check.', async () => {
const { data, status } = await client.get(
const { data, status, headers } = await client.get(
`/blob/${fileDid}/${fileCid.toString()}`,
{ responseType: 'arraybuffer' },
)
expect(status).toEqual(200)
expect(headers['content-type']).toEqual('image/jpeg')
expect(headers['content-security-policy']).toEqual(
`default-src 'none'; sandbox`,
)
expect(headers['x-content-type-options']).toEqual('nosniff')
await expect(verifyCidForBytes(fileCid, data)).resolves.toBeUndefined()
})

Expand Down
6 changes: 4 additions & 2 deletions packages/pds/src/api/com/atproto/sync/getBlob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ export default function (server: Server, ctx: AppContext) {
}
const cid = CID.parse(params.cid)
const blobStream = await ctx.blobstore.getStream(cid)
res.setHeader('Content-Length', found.size)
// @TODO better codegen for */* mimetype
res.setHeader('content-length', found.size)
res.setHeader('x-content-type-options', 'nosniff')
res.setHeader('content-security-policy', `default-src 'none'; sandbox`)
return {
// @TODO better codegen for */* mimetype
encoding: (found.mimeType || 'application/octet-stream') as '*/*',
body: blobStream,
}
Expand Down
12 changes: 7 additions & 5 deletions packages/pds/tests/file-uploads.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,16 @@ describe('file uploads', () => {
})

it('can fetch the file after being referenced', async () => {
const fetchedFile = await aliceAgent.api.com.atproto.sync.getBlob({
const { headers, data } = await aliceAgent.api.com.atproto.sync.getBlob({
did: alice.did,
cid: smallBlob.ref.toString(),
})
expect(fetchedFile.headers['content-type']).toEqual('image/jpeg')
expect(
uint8arrays.equals(smallFile, new Uint8Array(fetchedFile.data)),
).toBeTruthy()
expect(headers['content-type']).toEqual('image/jpeg')
expect(headers['content-security-policy']).toEqual(
`default-src 'none'; sandbox`,
)
expect(headers['x-content-type-options']).toEqual('nosniff')
expect(uint8arrays.equals(smallFile, new Uint8Array(data))).toBeTruthy()
})

it('serves the referenced blob', async () => {
Expand Down

0 comments on commit 3d1b3b3

Please sign in to comment.