fix: json parse crashes in monitor model with safe parsing (#6767)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Dharun Ashokkumar 2026-01-20 01:54:39 +05:30 committed by GitHub
parent f8652c27af
commit f8d494a03d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 83 additions and 122 deletions

View File

@ -1746,6 +1746,55 @@ class Monitor extends BeanModel {
}
}
// Validate JSON fields to prevent invalid JSON from being stored in database
if (this.kafkaProducerBrokers) {
try {
JSON.parse(this.kafkaProducerBrokers);
} catch (e) {
throw new Error(`Kafka Producer Brokers must be valid JSON: ${e.message}`);
}
}
if (this.kafkaProducerSaslOptions) {
try {
JSON.parse(this.kafkaProducerSaslOptions);
} catch (e) {
throw new Error(`Kafka Producer SASL Options must be valid JSON: ${e.message}`);
}
}
if (this.rabbitmqNodes) {
try {
JSON.parse(this.rabbitmqNodes);
} catch (e) {
throw new Error(`RabbitMQ Nodes must be valid JSON: ${e.message}`);
}
}
if (this.conditions) {
try {
JSON.parse(this.conditions);
} catch (e) {
throw new Error(`Conditions must be valid JSON: ${e.message}`);
}
}
if (this.headers) {
try {
JSON.parse(this.headers);
} catch (e) {
throw new Error(`Headers must be valid JSON: ${e.message}`);
}
}
if (this.accepted_statuscodes_json) {
try {
JSON.parse(this.accepted_statuscodes_json);
} catch (e) {
throw new Error(`Accepted status codes must be valid JSON: ${e.message}`);
}
}
if (this.type === "ping") {
// ping parameters validation
if (this.packetSize && (this.packetSize < PING_PACKET_SIZE_MIN || this.packetSize > PING_PACKET_SIZE_MAX)) {

View File

@ -10,99 +10,12 @@
*/
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CONSOLE_STYLE_FgViolet =
exports.CONSOLE_STYLE_FgLightBlue =
exports.CONSOLE_STYLE_FgLightGreen =
exports.CONSOLE_STYLE_FgOrange =
exports.CONSOLE_STYLE_FgGray =
exports.CONSOLE_STYLE_FgWhite =
exports.CONSOLE_STYLE_FgCyan =
exports.CONSOLE_STYLE_FgMagenta =
exports.CONSOLE_STYLE_FgBlue =
exports.CONSOLE_STYLE_FgYellow =
exports.CONSOLE_STYLE_FgGreen =
exports.CONSOLE_STYLE_FgRed =
exports.CONSOLE_STYLE_FgBlack =
exports.CONSOLE_STYLE_Hidden =
exports.CONSOLE_STYLE_Reverse =
exports.CONSOLE_STYLE_Blink =
exports.CONSOLE_STYLE_Underscore =
exports.CONSOLE_STYLE_Dim =
exports.CONSOLE_STYLE_Bright =
exports.CONSOLE_STYLE_Reset =
exports.RESPONSE_BODY_LENGTH_MAX =
exports.RESPONSE_BODY_LENGTH_DEFAULT =
exports.PING_PER_REQUEST_TIMEOUT_DEFAULT =
exports.PING_PER_REQUEST_TIMEOUT_MAX =
exports.PING_PER_REQUEST_TIMEOUT_MIN =
exports.PING_COUNT_DEFAULT =
exports.PING_COUNT_MAX =
exports.PING_COUNT_MIN =
exports.PING_GLOBAL_TIMEOUT_DEFAULT =
exports.PING_GLOBAL_TIMEOUT_MAX =
exports.PING_GLOBAL_TIMEOUT_MIN =
exports.PING_PACKET_SIZE_DEFAULT =
exports.PING_PACKET_SIZE_MAX =
exports.PING_PACKET_SIZE_MIN =
exports.MIN_INTERVAL_SECOND =
exports.MAX_INTERVAL_SECOND =
exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND =
exports.SQL_DATETIME_FORMAT =
exports.SQL_DATE_FORMAT =
exports.STATUS_PAGE_MAINTENANCE =
exports.STATUS_PAGE_PARTIAL_DOWN =
exports.STATUS_PAGE_ALL_UP =
exports.STATUS_PAGE_ALL_DOWN =
exports.MAINTENANCE =
exports.PENDING =
exports.UP =
exports.DOWN =
exports.appName =
exports.isNode =
exports.isDev =
void 0;
exports.TYPES_WITH_DOMAIN_EXPIRY_SUPPORT_VIA_FIELD =
exports.evaluateJsonQuery =
exports.intHash =
exports.localToUTC =
exports.utcToLocal =
exports.utcToISODateTime =
exports.isoToUTCDateTime =
exports.parseTimeFromTimeObject =
exports.parseTimeObject =
exports.getMonitorRelativeURL =
exports.genSecret =
exports.getCryptoRandomInt =
exports.getRandomInt =
exports.getRandomArbitrary =
exports.TimeLogger =
exports.polyfill =
exports.log =
exports.debug =
exports.ucfirst =
exports.sleep =
exports.flipStatus =
exports.badgeConstants =
exports.CONSOLE_STYLE_BgGray =
exports.CONSOLE_STYLE_BgWhite =
exports.CONSOLE_STYLE_BgCyan =
exports.CONSOLE_STYLE_BgMagenta =
exports.CONSOLE_STYLE_BgBlue =
exports.CONSOLE_STYLE_BgYellow =
exports.CONSOLE_STYLE_BgGreen =
exports.CONSOLE_STYLE_BgRed =
exports.CONSOLE_STYLE_BgBlack =
exports.CONSOLE_STYLE_FgPink =
exports.CONSOLE_STYLE_FgBrown =
void 0;
exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.RESPONSE_BODY_LENGTH_MAX = exports.RESPONSE_BODY_LENGTH_DEFAULT = exports.PING_PER_REQUEST_TIMEOUT_DEFAULT = exports.PING_PER_REQUEST_TIMEOUT_MAX = exports.PING_PER_REQUEST_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_GLOBAL_TIMEOUT_DEFAULT = exports.PING_GLOBAL_TIMEOUT_MAX = exports.PING_GLOBAL_TIMEOUT_MIN = exports.PING_PACKET_SIZE_DEFAULT = exports.PING_PACKET_SIZE_MAX = exports.PING_PACKET_SIZE_MIN = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0;
exports.TYPES_WITH_DOMAIN_EXPIRY_SUPPORT_VIA_FIELD = exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = void 0;
const dayjs_1 = require("dayjs");
const jsonata = require("jsonata");
exports.isDev = process.env.NODE_ENV === "development";
exports.isNode =
typeof process !== "undefined" &&
((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0
? void 0
: _a.node);
exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node);
const dayjs = exports.isNode ? require("dayjs") : dayjs_1.default;
exports.appName = "Uptime Kuma";
exports.DOWN = 0;
@ -257,7 +170,8 @@ class Logger {
let now;
if (dayjs.tz) {
now = dayjs.tz(new Date()).format();
} else {
}
else {
now = dayjs().format();
}
const levelColor = consoleLevelColors[level];
@ -276,7 +190,8 @@ class Logger {
}
modulePart = "[" + moduleColor + module + exports.CONSOLE_STYLE_Reset + "]";
levelPart = levelColor + `${level}:` + exports.CONSOLE_STYLE_Reset;
} else {
}
else {
timePart = now;
modulePart = `[${module}]`;
levelPart = `${level}:`;
@ -350,21 +265,21 @@ function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
exports.getRandomInt = getRandomInt;
const getRandomBytes = (
typeof window !== "undefined" && window.crypto
? function () {
return (numBytes) => {
const randomBytes = new Uint8Array(numBytes);
for (let i = 0; i < numBytes; i += 65536) {
window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536)));
}
return randomBytes;
};
}
: function () {
return require("crypto").randomBytes;
}
)();
const getRandomBytes = (typeof window !== "undefined" && window.crypto
?
function () {
return (numBytes) => {
const randomBytes = new Uint8Array(numBytes);
for (let i = 0; i < numBytes; i += 65536) {
window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536)));
}
return randomBytes;
};
}
:
function () {
return require("crypto").randomBytes;
})();
function getCryptoRandomInt(min, max) {
const range = max - min;
if (range >= Math.pow(2, 32)) {
@ -390,7 +305,8 @@ function getCryptoRandomInt(min, max) {
randomValue = randomValue & mask;
if (randomValue <= range) {
return min + randomValue;
} else {
}
else {
return getCryptoRandomInt(min, max);
}
}
@ -471,7 +387,8 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
let response;
try {
response = JSON.parse(data);
} catch (_a) {
}
catch (_a) {
response =
(typeof data === "object" || typeof data === "number") && !Buffer.isBuffer(data) ? data : data.toString();
}
@ -483,17 +400,13 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
if (Array.isArray(response)) {
const responseStr = JSON.stringify(response);
const truncatedResponse = responseStr.length > 25 ? responseStr.substring(0, 25) + "...]" : responseStr;
throw new Error(
"JSON query returned the array " +
truncatedResponse +
", but a primitive value is required. " +
"Modify your query to return a single value via [0] to get the first element or use an aggregation like $count(), $sum() or $boolean()."
);
throw new Error("JSON query returned the array " +
truncatedResponse +
", but a primitive value is required. " +
"Modify your query to return a single value via [0] to get the first element or use an aggregation like $count(), $sum() or $boolean().");
}
if (typeof response === "object" || response instanceof Date || typeof response === "function") {
throw new Error(
`The post-JSON query evaluated response from the server is of type ${typeof response}, which cannot be directly compared to the expected value`
);
throw new Error(`The post-JSON query evaluated response from the server is of type ${typeof response}, which cannot be directly compared to the expected value`);
}
let jsonQueryExpression;
switch (jsonPathOperator) {
@ -521,15 +434,14 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue
expected: expectedValue.toString(),
});
if (status === undefined) {
throw new Error(
"Query evaluation returned undefined. Check query syntax and the structure of the response data"
);
throw new Error("Query evaluation returned undefined. Check query syntax and the structure of the response data");
}
return {
status,
response,
};
} catch (err) {
}
catch (err) {
response = JSON.stringify(response);
response = response && response.length > 50 ? `${response.substring(0, 100)}… (truncated)` : response;
throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`);