more strict validation (#1)

in an attempt to preempt problems with non-deterministic (de-)serialization.
This commit is contained in:
Mikey 2023-05-09 19:19:00 +12:00 committed by GitHub
parent dc636c01c0
commit d1247afb06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 12 deletions

View File

@ -36,7 +36,12 @@ function validateShape(msg) {
function validateWho(msg) {
try {
base58.decode(msg.metadata.who)
const whoBuf = base58.decode(msg.metadata.who)
if (whoBuf.length !== 32) {
return new Error(
`invalid message: decoded "who" should be 32 bytes but was ${whoBuf.length}`
)
}
} catch (err) {
return new Error('invalid message: must have "who" as base58 string')
}
@ -44,7 +49,12 @@ function validateWho(msg) {
function validateMsgHash(str) {
try {
base58.decode(str)
const hashBuf = Buffer.from(base58.decode(str))
if (hashBuf.length !== 16) {
return new Error(
`invalid message: decoded hash should be 16 bytes but was ${hashBuf.length}`
)
}
} catch (err) {
return new Error(
`invalid message: msgHash ${str} should have been a base58 string`
@ -52,21 +62,30 @@ function validateMsgHash(str) {
}
}
function validateSize(msg) {
const {
metadata: { size },
} = msg
if (!Number.isSafeInteger(size) || size < 0) {
return new Error(`invalid message: "size" should be an unsigned integer`)
}
}
function validateSignature(msg) {
const { sig } = msg
if (typeof sig !== 'string') {
return new Error('invalid message: must have sig as a string')
}
let sigBuf
try {
base58.decode(sig)
} catch (err) {
return new Error('invalid message: sig must be a base58 string')
}
const sigBuf = Buffer.from(base58.decode(sig))
sigBuf = Buffer.from(base58.decode(sig))
if (sigBuf.length !== 64) {
// prettier-ignore
return new Error('invalid message: sig should be 64 bytes but was ' + sigBuf.length + ', on feed: ' + msg.metadata.who);
}
} catch (err) {
return new Error('invalid message: sig must be a base58 string')
}
const publicKeyBuf = Buffer.from(base58.decode(msg.metadata.who))
const signableBuf = Buffer.from(stringify(msg.metadata), 'utf8')
@ -93,9 +112,9 @@ function validateTangle(msg, tangle, tangleId) {
// prettier-ignore
return new Error('invalid message: prev must be an array, on feed: ' + msg.metadata.who);
}
if (typeof depth !== 'number') {
if (!Number.isSafeInteger(depth) || depth <= 0) {
// prettier-ignore
return new Error('invalid message: depth must be a number, on feed: ' + msg.metadata.who);
return new Error('invalid message: depth must be a positive integer, on feed: ' + msg.metadata.who);
}
if (tangle.isFeed()) {
const { type, who } = tangle.getFeed()
@ -202,6 +221,7 @@ function validate(msg, tangle, msgHash, rootHash) {
let err
if ((err = validateShape(msg))) return err
if ((err = validateWho(msg))) return err
if ((err = validateSize(msg))) return err
if (tangle.size() === 0) {
if ((err = validateTangleRoot(msg, msgHash, rootHash))) return err
} else {

View File

@ -7,11 +7,11 @@ interface Msg {
content: any | null, // any object, or null
metadata: {
hash: ContentHash, // blake3 hash of the `content` object serialized
size: number, // byte size of the `content` object serialized
size: number, // byte size (unsigned integer) of the `content` object serialized
tangles: {
// for each tangle this msg belongs to, identified by the tangle's root
[rootMsgHash: string]: {
depth: number, // maximum distance from this msg to the root
depth: number, // maximum distance (positive integer) from this msg to the root
prev: Array<MsgHash>, // list of msg hashes of existing msgs
},
},