mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-08-09 03:58:27 +08:00
Merge remote-tracking branch 'origin/master' into doubles-ss_master
# Conflicts: # server/database.js
This commit is contained in:
@@ -70,6 +70,7 @@ class Database {
|
||||
"patch-maintenance-table2.sql": true,
|
||||
"patch-add-gamedig-monitor.sql": true,
|
||||
"patch-add-google-analytics-status-page-tag.sql": true,
|
||||
"patch-http-body-encoding.sql": true
|
||||
"patch-monitor-tls.sql": true,
|
||||
};
|
||||
|
||||
@@ -497,6 +498,16 @@ class Database {
|
||||
const shmPath = Database.path + "-shm";
|
||||
const walPath = Database.path + "-wal";
|
||||
|
||||
// Make sure we have a backup to restore before deleting old db
|
||||
if (
|
||||
!fs.existsSync(this.backupPath)
|
||||
&& !fs.existsSync(shmPath)
|
||||
&& !fs.existsSync(walPath)
|
||||
) {
|
||||
log.error("db", "Backup file not found! Leaving database in failed state.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Delete patch failed db
|
||||
try {
|
||||
if (fs.existsSync(Database.path)) {
|
||||
|
@@ -111,6 +111,7 @@ class Monitor extends BeanModel {
|
||||
radiusCalledStationId: this.radiusCalledStationId,
|
||||
radiusCallingStationId: this.radiusCallingStationId,
|
||||
game: this.game,
|
||||
httpBodyEncoding: this.httpBodyEncoding
|
||||
};
|
||||
|
||||
if (includeSensitiveData) {
|
||||
@@ -146,7 +147,7 @@ class Monitor extends BeanModel {
|
||||
* @returns {Promise<LooseObject<any>[]>}
|
||||
*/
|
||||
async getTags() {
|
||||
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [ this.id ]);
|
||||
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ? ORDER BY tag.name", [ this.id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +207,7 @@ class Monitor extends BeanModel {
|
||||
let previousBeat = null;
|
||||
let retries = 0;
|
||||
|
||||
let prometheus = new Prometheus(this);
|
||||
this.prometheus = new Prometheus(this);
|
||||
|
||||
const beat = async () => {
|
||||
|
||||
@@ -275,17 +276,34 @@ class Monitor extends BeanModel {
|
||||
|
||||
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
|
||||
|
||||
let contentType = null;
|
||||
let bodyValue = null;
|
||||
|
||||
if (this.body && (typeof this.body === "string" && this.body.trim().length > 0)) {
|
||||
if (!this.httpBodyEncoding || this.httpBodyEncoding === "json") {
|
||||
try {
|
||||
bodyValue = JSON.parse(this.body);
|
||||
contentType = "application/json";
|
||||
} catch (e) {
|
||||
throw new Error("Your JSON body is invalid. " + e.message);
|
||||
}
|
||||
} else if (this.httpBodyEncoding === "xml") {
|
||||
bodyValue = this.body;
|
||||
contentType = "text/xml; charset=utf-8";
|
||||
}
|
||||
}
|
||||
|
||||
// Axios Options
|
||||
const options = {
|
||||
url: this.url,
|
||||
method: (this.method || "get").toLowerCase(),
|
||||
...(this.body ? { data: JSON.parse(this.body) } : {}),
|
||||
timeout: this.interval * 1000 * 0.8,
|
||||
headers: {
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||
"User-Agent": "Uptime-Kuma/" + version,
|
||||
...(this.headers ? JSON.parse(this.headers) : {}),
|
||||
...(contentType ? { "Content-Type": contentType } : {}),
|
||||
...(basicAuthHeader),
|
||||
...(this.headers ? JSON.parse(this.headers) : {})
|
||||
},
|
||||
maxRedirects: this.maxredirects,
|
||||
validateStatus: (status) => {
|
||||
@@ -293,6 +311,10 @@ class Monitor extends BeanModel {
|
||||
},
|
||||
};
|
||||
|
||||
if (bodyValue) {
|
||||
options.data = bodyValue;
|
||||
}
|
||||
|
||||
if (this.proxy_id) {
|
||||
const proxy = await R.load("proxy", this.proxy_id);
|
||||
|
||||
@@ -770,7 +792,7 @@ class Monitor extends BeanModel {
|
||||
await R.store(bean);
|
||||
|
||||
log.debug("monitor", `[${this.name}] prometheus.update`);
|
||||
prometheus.update(bean, tlsInfo);
|
||||
this.prometheus?.update(bean, tlsInfo);
|
||||
|
||||
previousBeat = bean;
|
||||
|
||||
@@ -854,15 +876,15 @@ class Monitor extends BeanModel {
|
||||
clearTimeout(this.heartbeatInterval);
|
||||
this.isStop = true;
|
||||
|
||||
this.prometheus().remove();
|
||||
this.prometheus?.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new prometheus instance
|
||||
* @returns {Prometheus}
|
||||
* Get prometheus instance
|
||||
* @returns {Prometheus|undefined}
|
||||
*/
|
||||
prometheus() {
|
||||
return new Prometheus(this);
|
||||
getPrometheus() {
|
||||
return this.prometheus;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -60,8 +60,11 @@ class StatusPage extends BeanModel {
|
||||
}
|
||||
|
||||
// OG Meta Tags
|
||||
head.append(`<meta property="og:title" content="${statusPage.title}" />`);
|
||||
head.append(`<meta property="og:description" content="${description155}" />`);
|
||||
let ogTitle = $("<meta property=\"og:title\" content=\"\" />").attr("content", statusPage.title);
|
||||
head.append(ogTitle);
|
||||
|
||||
let ogDescription = $("<meta property=\"og:description\" content=\"\" />").attr("content", description155);
|
||||
head.append(ogDescription);
|
||||
|
||||
// Preload data
|
||||
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
|
||||
|
@@ -42,7 +42,7 @@ class Slack extends NotificationProvider {
|
||||
const time = heartbeatJSON["time"];
|
||||
const textMsg = "Uptime Kuma Alert";
|
||||
let data = {
|
||||
"text": monitorJSON ? textMsg + `: ${monitorJSON.name}` : textMsg,
|
||||
"text": `${textMsg}\n${msg}`,
|
||||
"channel": notification.slackchannel,
|
||||
"username": notification.slackusername,
|
||||
"icon_emoji": notification.slackiconemo,
|
||||
|
@@ -9,11 +9,18 @@ class Telegram extends NotificationProvider {
|
||||
let okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
let params = {
|
||||
chat_id: notification.telegramChatID,
|
||||
text: msg,
|
||||
disable_notification: notification.telegramSendSilently ?? false,
|
||||
protect_content: notification.telegramProtectContent ?? false,
|
||||
};
|
||||
if (notification.telegramMessageThreadID) {
|
||||
params.message_thread_id = notification.telegramMessageThreadID;
|
||||
}
|
||||
|
||||
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||
params: {
|
||||
chat_id: notification.telegramChatID,
|
||||
text: msg,
|
||||
},
|
||||
params: params,
|
||||
});
|
||||
return okMsg;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
let express = require("express");
|
||||
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, send403 } = require("../util-server");
|
||||
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, sendHttpError } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const apicache = require("../modules/apicache");
|
||||
const Monitor = require("../model/monitor");
|
||||
@@ -175,7 +175,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -242,7 +242,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -303,7 +303,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -373,7 +373,7 @@ router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -464,7 +464,7 @@ router.get("/api/badge/:id/cert-exp", cache("5 minutes"), async (request, respon
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -536,7 +536,7 @@ router.get("/api/badge/:id/response", cache("5 minutes"), async (request, respon
|
||||
response.type("image/svg+xml");
|
||||
response.send(svg);
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -2,7 +2,7 @@ let express = require("express");
|
||||
const apicache = require("../modules/apicache");
|
||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||
const StatusPage = require("../model/status_page");
|
||||
const { allowDevAllOrigin, send403 } = require("../util-server");
|
||||
const { allowDevAllOrigin, sendHttpError } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const Monitor = require("../model/monitor");
|
||||
|
||||
@@ -44,10 +44,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons
|
||||
let statusPageData = await StatusPage.getStatusPageData(statusPage);
|
||||
|
||||
if (!statusPageData) {
|
||||
response.statusCode = 404;
|
||||
response.json({
|
||||
msg: "Not Found"
|
||||
});
|
||||
sendHttpError(response, "Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -55,7 +52,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons
|
||||
response.json(statusPageData);
|
||||
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,7 +100,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -119,10 +116,7 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
|
||||
]);
|
||||
|
||||
if (!statusPage) {
|
||||
response.statusCode = 404;
|
||||
response.json({
|
||||
msg: "Not Found"
|
||||
});
|
||||
sendHttpError(response, "Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,7 +135,7 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
send403(response, error.message);
|
||||
sendHttpError(response, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -677,9 +677,6 @@ let needSetup = false;
|
||||
throw new Error("Permission denied.");
|
||||
}
|
||||
|
||||
// Reset Prometheus labels
|
||||
server.monitorList[monitor.id]?.prometheus()?.remove();
|
||||
|
||||
bean.name = monitor.name;
|
||||
bean.type = monitor.type;
|
||||
bean.url = monitor.url;
|
||||
@@ -732,6 +729,7 @@ let needSetup = false;
|
||||
bean.radiusCalledStationId = monitor.radiusCalledStationId;
|
||||
bean.radiusCallingStationId = monitor.radiusCallingStationId;
|
||||
bean.radiusSecret = monitor.radiusSecret;
|
||||
bean.httpBodyEncoding = monitor.httpBodyEncoding;
|
||||
|
||||
bean.validate();
|
||||
|
||||
|
@@ -9,10 +9,10 @@ let gameList = null;
|
||||
|
||||
/**
|
||||
* Get a game list via GameDig
|
||||
* @returns {any[]}
|
||||
* @returns {Object[]} list of games supported by GameDig
|
||||
*/
|
||||
function getGameList() {
|
||||
if (!gameList) {
|
||||
if (gameList == null) {
|
||||
gameList = gameResolver._readGames().games.sort((a, b) => {
|
||||
if ( a.pretty < b.pretty ) {
|
||||
return -1;
|
||||
@@ -22,9 +22,8 @@ function getGameList() {
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
return gameList;
|
||||
}
|
||||
return gameList;
|
||||
}
|
||||
|
||||
module.exports.generalSocketHandler = (socket, server) => {
|
||||
|
@@ -292,14 +292,23 @@ exports.postgresQuery = function (connectionString, query) {
|
||||
client.end();
|
||||
} else {
|
||||
// Connected here
|
||||
client.query(query, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
try {
|
||||
// No query provided by user, use SELECT 1
|
||||
if (!query || (typeof query === "string" && query.trim() === "")) {
|
||||
query = "SELECT 1";
|
||||
}
|
||||
client.end();
|
||||
});
|
||||
|
||||
client.query(query, (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
client.end();
|
||||
});
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -323,7 +332,7 @@ exports.mysqlQuery = function (connectionString, query) {
|
||||
reject(err);
|
||||
})
|
||||
.finally(() => {
|
||||
connection.end();
|
||||
connection.destroy();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -730,15 +739,27 @@ exports.filterAndJoin = (parts, connector = "") => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a 403 response
|
||||
* Send an Error response
|
||||
* @param {Object} res Express response object
|
||||
* @param {string} [msg=""] Message to send
|
||||
*/
|
||||
module.exports.send403 = (res, msg = "") => {
|
||||
res.status(403).json({
|
||||
"status": "fail",
|
||||
"msg": msg,
|
||||
});
|
||||
module.exports.sendHttpError = (res, msg = "") => {
|
||||
if (msg.includes("SQLITE_BUSY") || msg.includes("SQLITE_LOCKED")) {
|
||||
res.status(503).json({
|
||||
"status": "fail",
|
||||
"msg": msg,
|
||||
});
|
||||
} else if (msg.toLowerCase().includes("not found")) {
|
||||
res.status(404).json({
|
||||
"status": "fail",
|
||||
"msg": msg,
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({
|
||||
"status": "fail",
|
||||
"msg": msg,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function timeObjectConvertTimezone(obj, timezone, timeObjectToUTC = true) {
|
||||
|
Reference in New Issue
Block a user