Skip to content

Commit 4526369

Browse files
author
Alan Shaw
authored
fix: verify CAR blocks with all supported hashes (#2460)
1 parent 0e34b13 commit 4526369

5 files changed

Lines changed: 83 additions & 27 deletions

File tree

packages/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"@nftstorage/ipfs-cluster": "^5.0.1",
2828
"@noble/ed25519": "^1.6.1",
2929
"@supabase/postgrest-js": "^0.34.1",
30+
"@web3-storage/car-block-validator": "^1.2.0",
3031
"cardex": "^1.0.0",
3132
"ipfs-car": "^0.6.1",
3233
"it-last": "^2.0.0",

packages/api/src/routes/nfts-upload.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as raw from 'multiformats/codecs/raw'
55
import * as cbor from '@ipld/dag-cbor'
66
import * as pb from '@ipld/dag-pb'
77
import { Block } from 'multiformats/block'
8-
import { sha256 } from 'multiformats/hashes/sha2'
8+
import { validateBlock } from '@web3-storage/car-block-validator'
99
import { HTTPError, InvalidCarError } from '../errors.js'
1010
import { createCarCid } from '../utils/car.js'
1111
import { JSONResponse } from '../utils/json-response.js'
@@ -270,13 +270,13 @@ export async function carStat(carBlob, { structure } = {}) {
270270
if (blockSize > MAX_BLOCK_SIZE) {
271271
throw new Error(`block too big: ${blockSize} > ${MAX_BLOCK_SIZE}`)
272272
}
273-
if (block.cid.multihash.code === sha256.code) {
274-
const ourHash = await sha256.digest(block.bytes)
275-
if (!equals(ourHash.digest, block.cid.multihash.digest)) {
276-
throw new InvalidCarError(
277-
`block data does not match CID for ${block.cid.toString()}`
278-
)
279-
}
273+
try {
274+
// @ts-expect-error CID type mismatch
275+
await validateBlock(block)
276+
} catch (/** @type {any} */ err) {
277+
throw new InvalidCarError(
278+
`failed hash verification: ${block.cid.toString()}: ${err.message}`
279+
)
280280
}
281281
if (!rawRootBlock && block.cid.equals(rootCid)) {
282282
rawRootBlock = block
1.28 KB
Binary file not shown.

packages/api/test/nfts-upload.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@ import {
2121
} from './scripts/test-context.js'
2222
import { File } from 'nft.storage/src/platform.js'
2323
import crypto from 'node:crypto'
24+
import fs from 'node:fs'
25+
import { fileURLToPath } from 'node:url'
26+
import path from 'node:path'
2427
import { FormData } from 'undici'
2528
import { createCarCid } from '../src/utils/car.js'
2629

30+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
31+
2732
test.before(async (t) => {
2833
const linkdexUrl = 'http://fake.api.net'
2934
await setupMiniflareContext(t, { overrides: { LINKDEX_URL: linkdexUrl } })
@@ -806,6 +811,32 @@ test.serial('should write dudewhere index', async (t) => {
806811
t.is(r2Objects.objects[0].key, `${root}/${carCid}`)
807812
})
808813

814+
test.serial('should fail upload for corrupt CAR', async (t) => {
815+
const client = await createClientWithUser(t)
816+
const mf = getMiniflareContext(t)
817+
const carBytes = await fs.promises.readFile(
818+
path.join(__dirname, 'fixtures', 'corrupt.car')
819+
)
820+
const res = await mf.dispatchFetch('http://miniflare.test/upload', {
821+
method: 'POST',
822+
headers: {
823+
Authorization: `Bearer ${client.token}`,
824+
'Content-Type': 'application/car',
825+
},
826+
body: carBytes,
827+
})
828+
829+
t.is(res.status, 400)
830+
831+
const { ok, error } = await res.json()
832+
t.is(ok, false)
833+
t.is(error.code, 'ERROR_INVALID_CAR')
834+
t.is(
835+
error.message,
836+
'Invalid CAR file received: failed hash verification: bafk2bzaceda5oo2f5wmcwfmqbqkxzdwzszc2bhqnj4lpygliqna7bmbkmzwh4: CID hash does not match bytes'
837+
)
838+
})
839+
809840
/**
810841
* @param {Uint8Array} data
811842
*/

yarn.lock

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3006,14 +3006,30 @@
30063006
resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121"
30073007
integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw==
30083008

3009-
"@multiformats/murmur3@^1.0.3":
3009+
"@multiformats/blake2@^1.0.13":
3010+
version "1.0.13"
3011+
resolved "https://registry.yarnpkg.com/@multiformats/blake2/-/blake2-1.0.13.tgz#ab0c471da28df55eb7c16339e25ba9571259c2d7"
3012+
integrity sha512-T1Kzya0wjj85CaVeRSpJ858EnSvW1pw94GSitxYf84VsNdv5XYbJ6QG8y26Ft1bVALzrUCmqkQrR53QHSyu6RA==
3013+
dependencies:
3014+
blakejs "^1.1.1"
3015+
multiformats "^9.5.4"
3016+
3017+
"@multiformats/murmur3@^1.0.3", "@multiformats/murmur3@^1.1.3":
30103018
version "1.1.3"
30113019
resolved "https://registry.yarnpkg.com/@multiformats/murmur3/-/murmur3-1.1.3.tgz#70349166992e5f981f1ddff0200fa775b2bf6606"
30123020
integrity sha512-wAPLUErGR8g6Lt+bAZn6218k9YQPym+sjszsXL6o4zfxbA22P+gxWZuuD9wDbwL55xrKO5idpcuQUX7/E3oHcw==
30133021
dependencies:
30143022
multiformats "^9.5.4"
30153023
murmurhash3js-revisited "^3.0.0"
30163024

3025+
"@multiformats/sha3@^2.0.15":
3026+
version "2.0.17"
3027+
resolved "https://registry.yarnpkg.com/@multiformats/sha3/-/sha3-2.0.17.tgz#bcfd2d6d7c44a61ced79a2c4dd45acd9ebbfb8d7"
3028+
integrity sha512-7ik6pk178qLO2cpNucgf48UnAOBMkq/2H92DP4SprZOJqM9zqbVaKS7XyYW6UvhRsDJ3wi921fYv1ihTtQHLtA==
3029+
dependencies:
3030+
js-sha3 "^0.8.0"
3031+
multiformats "^9.5.4"
3032+
30173033
"@next/bundle-analyzer@^12.0.7":
30183034
version "12.2.5"
30193035
resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.2.5.tgz#6aca94359b1a1f933dfb0a89d5f4d0b1fb86e3e5"
@@ -5249,6 +5265,17 @@
52495265
dependencies:
52505266
web-streams-polyfill "^3.1.1"
52515267

5268+
"@web3-storage/car-block-validator@^1.2.0":
5269+
version "1.2.0"
5270+
resolved "https://registry.yarnpkg.com/@web3-storage/car-block-validator/-/car-block-validator-1.2.0.tgz#533ea6b22059606ed19e906434a50c0a16c07283"
5271+
integrity sha512-KKQ/M5WtpH/JlkX+bQYKzdG4azmSF495T7vpewje2xh7MBh1d94/BLblxCcLM/larWvXDxOkbAyTTdlECAAuUw==
5272+
dependencies:
5273+
"@multiformats/blake2" "^1.0.13"
5274+
"@multiformats/murmur3" "^1.1.3"
5275+
"@multiformats/sha3" "^2.0.15"
5276+
multiformats "9.9.0"
5277+
uint8arrays "^3.1.1"
5278+
52525279
"@web3-storage/multipart-parser@^1.0.0":
52535280
version "1.0.0"
52545281
resolved "https://registry.yarnpkg.com/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz#6b69dc2a32a5b207ba43e556c25cc136a56659c4"
@@ -6414,7 +6441,7 @@ blake3-wasm@^2.1.5:
64146441
resolved "https://registry.yarnpkg.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz#b22dbb84bc9419ed0159caa76af4b1b132e6ba52"
64156442
integrity sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==
64166443

6417-
blakejs@^1.1.0:
6444+
blakejs@^1.1.0, blakejs@^1.1.1:
64186445
version "1.2.1"
64196446
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814"
64206447
integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==
@@ -14817,16 +14844,16 @@ multicodec@^3.0.1, multicodec@^3.2.1:
1481714844
uint8arrays "^3.0.0"
1481814845
varint "^6.0.0"
1481914846

14847+
multiformats@9.9.0, multiformats@^9.6.5:
14848+
version "9.9.0"
14849+
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37"
14850+
integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==
14851+
1482014852
multiformats@^9.0.0, multiformats@^9.0.4, multiformats@^9.4.13, multiformats@^9.4.2, multiformats@^9.4.5, multiformats@^9.4.7, multiformats@^9.5.4, multiformats@^9.6.3, multiformats@^9.6.4:
1482114853
version "9.7.1"
1482214854
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.7.1.tgz#ab348e5fd6f8e7fb3fd56033211bda48854e2173"
1482314855
integrity sha512-TaVmGEBt0fhxiNJMGphBfB+oGvUxFs8KgGvgl8d3C+GWtrFcvXdJ2196eg+dYhmSFClmgFfSfJEklo+SZzdNuw==
1482414856

14825-
multiformats@^9.6.5:
14826-
version "9.9.0"
14827-
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37"
14828-
integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==
14829-
1483014857
multihashes@^4.0.1, multihashes@^4.0.2:
1483114858
version "4.0.3"
1483214859
resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-4.0.3.tgz#426610539cd2551edbf533adeac4c06b3b90fb05"
@@ -16848,16 +16875,11 @@ prettier-linter-helpers@^1.0.0:
1684816875
dependencies:
1684916876
fast-diff "^1.1.2"
1685016877

16851-
prettier@2.5.1, prettier@^2.5.1:
16878+
prettier@2.5.1, "prettier@>=2.2.1 <=2.3.0", prettier@^2.5.1:
1685216879
version "2.5.1"
1685316880
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
1685416881
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
1685516882

16856-
"prettier@>=2.2.1 <=2.3.0":
16857-
version "2.3.0"
16858-
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
16859-
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
16860-
1686116883
pretty-error@^2.1.1:
1686216884
version "2.1.2"
1686316885
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
@@ -20022,12 +20044,7 @@ typedoc@^0.22.14:
2002220044
minimatch "^5.1.0"
2002320045
shiki "^0.10.1"
2002420046

20025-
typescript@4.4.4:
20026-
version "4.4.4"
20027-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c"
20028-
integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==
20029-
20030-
typescript@4.5.3:
20047+
typescript@4.4.4, typescript@4.5.3:
2003120048
version "4.5.3"
2003220049
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c"
2003320050
integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==
@@ -20070,6 +20087,13 @@ uint8arrays@^3.0.0:
2007020087
dependencies:
2007120088
multiformats "^9.4.2"
2007220089

20090+
uint8arrays@^3.1.1:
20091+
version "3.1.1"
20092+
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0"
20093+
integrity sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==
20094+
dependencies:
20095+
multiformats "^9.4.2"
20096+
2007320097
unbox-primitive@^1.0.2:
2007420098
version "1.0.2"
2007520099
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"

0 commit comments

Comments
 (0)