feat: add explicit value checking on saving to / reading from budget

This commit is contained in:
Tom French 2022-07-29 01:06:55 +01:00 committed by James Long
parent 5f0da9deb8
commit 4b83552ddf
3 changed files with 24 additions and 5 deletions

View file

@ -3,10 +3,11 @@ import * as db from '../db';
import * as prefs from '../prefs';
import * as sheet from '../sheet';
import { batchMessages } from '../sync';
import { safeNumber } from './util';
async function getSheetValue(sheetName, cell) {
const node = await sheet.getCell(sheetName, cell);
return typeof node.value === 'number' ? node.value : 0;
return safeNumber(typeof node.value === 'number' ? node.value : 0);
}
// We want to only allow the positive movement of money back and
@ -71,9 +72,7 @@ export function getBudget({ category, month }) {
}
export function setBudget({ category, month, amount }) {
if (typeof amount !== 'number') {
amount = 0;
}
amount = safeNumber(typeof amount === 'number' ? amount : 0);
const table = getBudgetTable();
let existing = db.firstSync(

View file

@ -1,6 +1,6 @@
import * as monthUtils from '../../shared/months';
import * as sheet from '../sheet';
import { number, sumAmounts, flatten2, unflatten2 } from './util';
import { number, sumAmounts, flatten2, unflatten2, safeNumber } from './util';
const { resolveName } = require('../spreadsheet/util');

View file

@ -19,3 +19,23 @@ export function unflatten2(arr) {
}
return res;
}
// Note that we don't restrict values to `Number.MIN_SAFE_INTEGER <= value <= Number.MAX_SAFE_INTEGER`
// where `Number.MAX_SAFE_INTEGER == 2^53 - 1` but a smaller range over `-(2^43-1) <= value <= 2^43 - 1`.
// This ensure that the number is accurate not just for the integer component but for 3 decimal places also.
//
// This gives us the guarantee that can use `safeNumber` on number whether they are unscaled user inputs
// or they have been converted to integers (using `amountToInteger`).
const MAX_SAFE_NUMBER = 2 ** 43 - 1;
const MIN_SAFE_NUMBER = -MAX_SAFE_NUMBER;
export function safeNumber(value) {
value = number(value);
if (value > MAX_SAFE_NUMBER || value < MIN_SAFE_NUMBER) {
throw new Error(
"Can't safely perform arithmetic with number: " + JSON.stringify(value)
);
}
return value;
}