Add Zod for runtime and compile-time type checking, use it in logging code

This commit is contained in:
Evan Hahn 2021-04-01 12:37:10 -05:00 committed by Josh Perez
parent c711fbe0c0
commit eb97c1194a
6 changed files with 58 additions and 56 deletions

View file

@ -1,6 +1,7 @@
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as z from 'zod';
import FormData from 'form-data';
import { gzip } from 'zlib';
import pify from 'pify';
@ -9,28 +10,21 @@ import { getUserAgent } from '../util/getUserAgent';
const BASE_URL = 'https://debuglogs.org';
const isObject = (value: unknown): value is Record<string, unknown> =>
typeof value === 'object' && !Array.isArray(value) && Boolean(value);
const tokenBodySchema = z
.object({
fields: z.record(z.unknown()),
url: z.string(),
})
.nonstrict();
const parseTokenBody = (
body: unknown
rawBody: unknown
): { fields: Record<string, unknown>; url: string } => {
if (!isObject(body)) {
throw new Error('Token body is not an object');
}
const body = tokenBodySchema.parse(rawBody);
const { fields, url } = body as Record<string, unknown>;
if (!isObject(fields)) {
throw new Error('Token body\'s "fields" key is not an object');
}
if (typeof url !== 'string') {
throw new Error('Token body\'s "url" key is not a string');
}
let parsedUrl: URL;
try {
parsedUrl = new URL(url);
parsedUrl = new URL(body.url);
} catch (err) {
throw new Error("Token body's URL was not a valid URL");
}
@ -38,7 +32,7 @@ const parseTokenBody = (
throw new Error("Token body's URL was not HTTPS");
}
return { fields, url };
return body;
};
export const uploadDebugLogs = async (

View file

@ -1,6 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import * as z from 'zod';
import * as pino from 'pino';
import { redactAll } from '../../js/modules/privacy';
import { missingCaseError } from '../util/missingCaseError';
@ -19,37 +20,14 @@ export enum LogLevel {
// These match [Pino's core fields][1].
// [1]: https://getpino.io/#/?id=usage
export type LogEntryType = {
level: LogLevel;
msg: string;
time: string;
};
const logEntrySchema = z.object({
level: z.nativeEnum(LogLevel),
msg: z.string(),
time: z.string().refine(value => !Number.isNaN(new Date(value).getTime())),
});
export type LogEntryType = z.infer<typeof logEntrySchema>;
const logLevels = new Set<LogLevel>([
LogLevel.Fatal,
LogLevel.Error,
LogLevel.Warn,
LogLevel.Info,
LogLevel.Debug,
LogLevel.Trace,
]);
function isLogLevel(value: unknown): value is LogLevel {
return typeof value === 'number' && logLevels.has(value);
}
function isValidTime(value: unknown): value is string {
return typeof value === 'string' && !Number.isNaN(new Date(value).getTime());
}
export function isLogEntry(value: unknown): value is LogEntryType {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return false;
}
const { level, time, msg } = value as Record<string, unknown>;
return typeof msg === 'string' && isLogLevel(level) && isValidTime(time);
}
export const isLogEntry = logEntrySchema.check.bind(logEntrySchema);
export function getLogLevelString(value: LogLevel): pino.Level {
switch (value) {

View file

@ -14802,7 +14802,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.js",
"line": " form.append('key', fields.key);",
"lineNumber": 45,
"lineNumber": 61,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14810,7 +14810,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.js",
"line": " form.append(key, value);",
"lineNumber": 49,
"lineNumber": 65,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14818,7 +14818,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.js",
"line": " form.append('Content-Type', contentType);",
"lineNumber": 53,
"lineNumber": 69,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14826,7 +14826,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.js",
"line": " form.append('file', contentBuffer, {",
"lineNumber": 54,
"lineNumber": 70,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14834,7 +14834,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.ts",
"line": " form.append('key', fields.key);",
"lineNumber": 55,
"lineNumber": 49,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14842,7 +14842,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.ts",
"line": " form.append(key, value);",
"lineNumber": 59,
"lineNumber": 53,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14850,7 +14850,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.ts",
"line": " form.append('Content-Type', contentType);",
"lineNumber": 64,
"lineNumber": 58,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},
@ -14858,7 +14858,7 @@
"rule": "jQuery-append(",
"path": "ts/logging/debuglogs.ts",
"line": " form.append('file', contentBuffer, {",
"lineNumber": 65,
"lineNumber": 59,
"reasonCategory": "falseMatch",
"updated": "2020-12-17T18:08:07.752Z"
},