diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 214216228..703a50c2f 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -3058,3 +3058,27 @@ Signal Desktop makes use of the following open source projects. of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS + +## zod + + MIT License + + Copyright (c) 2020 Colin McDonnell + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/package.json b/package.json index 3e884f885..eca00f049 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,8 @@ "underscore": "1.9.0", "uuid": "3.3.2", "websocket": "1.0.28", - "zkgroup": "https://github.com/signalapp/signal-zkgroup-node.git#2d7db946cc88492b65cc66e9aa9de0c9e664fd8d" + "zkgroup": "https://github.com/signalapp/signal-zkgroup-node.git#2d7db946cc88492b65cc66e9aa9de0c9e664fd8d", + "zod": "1.11.13" }, "devDependencies": { "@babel/core": "7.7.7", diff --git a/ts/logging/debuglogs.ts b/ts/logging/debuglogs.ts index bce9cce41..bffaf95a2 100644 --- a/ts/logging/debuglogs.ts +++ b/ts/logging/debuglogs.ts @@ -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 => - 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; 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; - - 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 ( diff --git a/ts/logging/shared.ts b/ts/logging/shared.ts index 69f367cfc..d78b28d6b 100644 --- a/ts/logging/shared.ts +++ b/ts/logging/shared.ts @@ -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; -const logLevels = new Set([ - 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; - - return typeof msg === 'string' && isLogLevel(level) && isValidTime(time); -} +export const isLogEntry = logEntrySchema.check.bind(logEntrySchema); export function getLogLevelString(value: LogLevel): pino.Level { switch (value) { diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index d3f988b0c..19cd35524 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -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" }, diff --git a/yarn.lock b/yarn.lock index 02670e08c..8746388f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17620,3 +17620,8 @@ zip-stream@^1.2.0: ffi-napi "2.4.5" ref-array-napi "1.2.0" ref-napi "1.4.2" + +zod@1.11.13: + version "1.11.13" + resolved "https://registry.yarnpkg.com/zod/-/zod-1.11.13.tgz#6acb1e52b670afeb816ce2e2ddf6ab359f9ea506" + integrity sha512-10+KA7eWa8g1hbKIXkOnhjJ4RKEwX85ECz3VJzP+pWkJOFKn76bHy1kG0d1JHBwmdElLcCsaB0O9HqIfT1vZnw==