fix(security): bound untrusted wire decoding
req: security/005
This commit is contained in:
@@ -117,12 +117,48 @@ async function openLog() {
|
||||
return requestResult(request);
|
||||
}
|
||||
|
||||
export function validateQueuedCommand(command) {
|
||||
if (!command || Object.getPrototypeOf(command) !== Object.prototype) {
|
||||
throw new TypeError("queued command must be an object");
|
||||
}
|
||||
if (command.schemaVersion !== COMMAND_SCHEMA) {
|
||||
throw new RangeError(`unsupported queued command schema version ${command.schemaVersion}`);
|
||||
}
|
||||
const boundedString = (field, maximum) => {
|
||||
const value = command[field];
|
||||
if (typeof value !== "string" || value.length === 0 || value.length > maximum) {
|
||||
throw new TypeError(`queued command ${field} is invalid`);
|
||||
}
|
||||
};
|
||||
boundedString("id", 256);
|
||||
boundedString("accountPartition", 128);
|
||||
boundedString("actor", 128);
|
||||
boundedString("session", 128);
|
||||
boundedString("cardId", 128);
|
||||
if (!Number.isSafeInteger(command.causal) || command.causal < 1) {
|
||||
throw new TypeError("queued command causal is invalid");
|
||||
}
|
||||
const queuedAt = command.queuedAt === undefined ? 0 : command.queuedAt;
|
||||
if (!Number.isSafeInteger(queuedAt) || queuedAt < 0) {
|
||||
throw new TypeError("queued command queuedAt is invalid");
|
||||
}
|
||||
if (command.kind !== "reorder_card") throw new TypeError(`unknown queued command kind ${command.kind}`);
|
||||
if (command.targetColumn !== "done") throw new TypeError(`unknown queued command target ${command.targetColumn}`);
|
||||
if (!["click", "drop", "keydown"].includes(command.eventKind)) {
|
||||
throw new TypeError(`unknown queued command event kind ${command.eventKind}`);
|
||||
}
|
||||
if (command.key !== null && (typeof command.key !== "string" || command.key.length > 64)) {
|
||||
throw new TypeError("queued command key is invalid");
|
||||
}
|
||||
return command.queuedAt === undefined ? { ...command, queuedAt } : command;
|
||||
}
|
||||
|
||||
async function pendingCommands(database) {
|
||||
const transaction = database.transaction(COMMANDS, "readonly");
|
||||
const done = transactionDone(transaction);
|
||||
const commands = await requestResult(transaction.objectStore(COMMANDS).index(ACCOUNT_INDEX).getAll(accountPartition));
|
||||
await done;
|
||||
return commands.sort((left, right) => left.causal - right.causal);
|
||||
return commands.map(validateQueuedCommand).sort((left, right) => left.causal - right.causal);
|
||||
}
|
||||
|
||||
async function removePendingCommand(database, commandId) {
|
||||
|
||||
Reference in New Issue
Block a user