3 ms·
const cached = new Map<string, Function>() export function as<T>(o: any, path: string, as: (o: any) => T | undefined) { try { let fn = cached.get(p
by 90s_dev 1y ago
const cached = new Map<string, Function>()
export function as<T>(o: any, path: string, as: (o: any) => T | undefined) {
try {
let fn = cached.get(path)
if (!fn) cached.set(path, fn = new Function('o', `return o.${path}`))
const v = fn(o)
return as(v) as T | undefined
}
catch (e) {
return undefined
}
}
as.number = (o: any) => (typeof o === 'number' ? o : undefined)
as.string = (o: any) => (typeof o === 'string' ? o : undefined)
as.boolean = (o: any) => (typeof o === 'boolean' ? o : undefined)
as.numbers = (len = 0) => (o: any) => (o instanceof Array && o.length >= len && o.every(c => typeof c === 'number') ? o : undefined)
as.strings = (len = 0) => (o: any) => (o instanceof Array && o.length >= len && o.every(c => typeof c === 'string') ? o : undefined)
const size = as(usrConfig, 'sys.size', as.numbers(2))
const fontpath = as(usrConfig, 'sys.font', as.string)
- rafram 1y agoGreat if that's the only validation you need, but I can't imagine using it in a real app, and there are some obvious bugs (e.g. never use `instanceof Array`).
- 90s_dev 1y agoArray.isArray isn't needed when you know your array isn't going to be deserialized e.g. via MessagePort. What other supposed bugs? And yes I'm aware this doesn't have a huge API surface. That's the whole point. If I already have a JSON object, I can reach into it and get either what I ask for or nothing. In many real world cases, this is enough.
- rafram 1y agolet someArray = [1, 2, , 4]; console.log(as.numbers(someArray) === someArray); // => true for (let number of numbers) { // This should be safe because I know everything in the array is a number, right? console.log(number.toFixed(2)); // => TypeError: number is undefined } I mean, it's probably fine if you're only ever getting your data from JSON.parse(). But I would hesitate to use this in production.
- 90s_dev 1y agoThe point is that it's layered. 1. Validate your Buffer/UInt8Array for valid size/encoding/etc first 2. Parse it to an object via JSON.parse or whatever your use-case needs 3. Reach into it with this function to get data if it matches the type you need This code only deals with #3 and makes a few assumptions about #2 (e.g. no undefined, typical JSON-like object, etc).
- Dylan16807 1y ago> I mean, it's probably fine if you're only ever getting your data from JSON.parse(). So 90% of use cases?
- rafram 1y agoSure, and then only 10% of your use cases contain easily exploitable vulnerabilities.
- Dylan16807 1y agoYou use a different function than Validate_Parsed_JSON in those cases. But most typescript programs are only going to need JSON-compatible input. Maybe some XML but that's also going to have similar formulaic output from your parser. If something can directly hand you a maliciously built data structure, you're probably designing your system wrong. Are you running untrusted javascript in the same interpreter? That's a very hard problem that should be avoided if at all possible. Basically, only working on JSON.parse is something to document but it's not at all a weird restriction, or a reason to balk at putting it into production.