Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #7329 from LiskHQ/7210_fix_codec
Browse files Browse the repository at this point in the history
Update lisk-codec to disallow decoding additional fields - Closes #7047
  • Loading branch information
ishantiw authored Jul 29, 2022
2 parents 96f8e50 + e386abd commit e98d0ec
Show file tree
Hide file tree
Showing 22 changed files with 473 additions and 146 deletions.
11 changes: 7 additions & 4 deletions elements/lisk-codec/src/boolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
export const writeBoolean = (value: boolean): Buffer =>
value ? Buffer.from('01', 'hex') : Buffer.from('00', 'hex');

export const readBoolean = (buffer: Buffer, offset: number): [boolean, number] => [
buffer[offset] !== 0x00,
1,
];
export const readBoolean = (buffer: Buffer, offset: number): [boolean, number] => {
const val = buffer[offset];
if (val !== 0x00 && val !== 0x01) {
throw new Error('Invalid boolean bytes.');
}
return [val !== 0x00, 1];
};
33 changes: 23 additions & 10 deletions elements/lisk-codec/src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { writeString, readString } from './string';
import { writeBytes, readBytes } from './bytes';
import { writeBoolean, readBoolean } from './boolean';
import { readKey } from './keys';
import { getDefaultValue } from './utils/default_value';

const _readers: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -139,8 +138,13 @@ export const readObject = (
result[typeSchema[0].propertyName] = arr;
index = nextOffset;
} else if (typeSchema[0].schemaProp.type === 'object') {
// It should be wire type 2 as it's object
const [, keySize] = readUInt32(message, index);
const [key, keySize] = readUInt32(message, index);
const [fieldNumber] = readKey(key);
// case where field number reading is not as expected from schema
if (fieldNumber !== typeSchema[0].schemaProp.fieldNumber) {
throw new Error('Invalid field number while decoding.');
}

index += keySize;
// Takeout the length
const [objectSize, objectSizeLength] = readUInt32(message, index);
Expand All @@ -149,26 +153,25 @@ export const readObject = (
result[typeSchema[0].propertyName] = obj;
index = nextOffset;
} else {
throw new Error('Invalid container type');
throw new Error('Invalid container type.');
}
continue;
}
if (typeSchema.schemaProp.type === 'object' || typeSchema.schemaProp.type === 'array') {
// typeSchema is header, and we ignore this
continue;
}
// case where message length is shorter than what the schema expects
if (message.length <= index) {
// assign default value
result[typeSchema.propertyName] = getDefaultValue(typeSchema.schemaProp.dataType as string);
continue;
throw new Error(
`Message does not contain a property for fieldNumber: ${typeSchema.schemaProp.fieldNumber}.`,
);
}
// Takeout the root wireType and field number
const [key, keySize] = readUInt32(message, index);
const [fieldNumber] = readKey(key);
if (fieldNumber !== typeSchema.schemaProp.fieldNumber) {
// assign default value
result[typeSchema.propertyName] = getDefaultValue(typeSchema.schemaProp.dataType as string);
continue;
throw new Error('Invalid field number while decoding.');
}
// Index is only incremented when the key is actually used
index += keySize;
Expand All @@ -181,6 +184,14 @@ export const readObject = (
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
result[typeSchema.propertyName] = scalarValue;
}

// case where message length is longer than what the schema expects
if (index !== terminateIndex) {
throw new Error(
`Invalid terminate index. Index is ${index} but terminateIndex is ${terminateIndex}`,
);
}

return [result, index];
};

Expand Down Expand Up @@ -230,6 +241,7 @@ export const readArray = (
result.push(res);
index = nextOffset;
}

return [result, index];
}
throw new Error('Invalid container type');
Expand Down Expand Up @@ -258,6 +270,7 @@ export const readArray = (
result.push(res);
index += wire2Size;
}

return [result, index];
}
const [, keySize] = readUInt32(message, index);
Expand Down
Loading

0 comments on commit e98d0ec

Please sign in to comment.