mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-18 04:04:41 -05:00
Merge branch 'louislam:master' into ntfy-bearer-authorization
This commit is contained in:
commit
11f4cb8725
@ -64,7 +64,7 @@
|
|||||||
"cy:run:unit": "npx cypress run --browser chrome --headless --config-file ./config/cypress.frontend.config.js",
|
"cy:run:unit": "npx cypress run --browser chrome --headless --config-file ./config/cypress.frontend.config.js",
|
||||||
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"",
|
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"",
|
||||||
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
|
||||||
"depoly-demo-server": "node extra/deploy-demo-server.js",
|
"deploy-demo-server": "node extra/deploy-demo-server.js",
|
||||||
"sort-contributors": "node extra/sort-contributors.js"
|
"sort-contributors": "node extra/sort-contributors.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2,7 +2,9 @@ const https = require("https");
|
|||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { Prometheus } = require("../prometheus");
|
const { Prometheus } = require("../prometheus");
|
||||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } = require("../../src/util");
|
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
|
||||||
|
SQL_DATETIME_FORMAT
|
||||||
|
} = require("../../src/util");
|
||||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery,
|
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery,
|
||||||
redisPingAsync, mongodbPing,
|
redisPingAsync, mongodbPing,
|
||||||
} = require("../util-server");
|
} = require("../util-server");
|
||||||
@ -1176,12 +1178,18 @@ class Monitor extends BeanModel {
|
|||||||
|
|
||||||
for (let notification of notificationList) {
|
for (let notification of notificationList) {
|
||||||
try {
|
try {
|
||||||
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
|
|
||||||
const heartbeatJSON = bean.toJSON();
|
const heartbeatJSON = bean.toJSON();
|
||||||
|
|
||||||
|
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
|
||||||
if (!heartbeatJSON["msg"]) {
|
if (!heartbeatJSON["msg"]) {
|
||||||
heartbeatJSON["msg"] = "N/A";
|
heartbeatJSON["msg"] = "N/A";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also provide the time in server timezone
|
||||||
|
heartbeatJSON["timezone"] = await UptimeKumaServer.getInstance().getTimezone();
|
||||||
|
heartbeatJSON["timezoneOffset"] = UptimeKumaServer.getInstance().getTimezoneOffset();
|
||||||
|
heartbeatJSON["localDateTime"] = dayjs.utc(heartbeatJSON["time"]).tz(heartbeatJSON["timezone"]).format(SQL_DATETIME_FORMAT);
|
||||||
|
|
||||||
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), heartbeatJSON);
|
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), heartbeatJSON);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("monitor", "Cannot send notification to " + notification.name);
|
log.error("monitor", "Cannot send notification to " + notification.name);
|
||||||
|
@ -10,7 +10,7 @@ class Mattermost extends NotificationProvider {
|
|||||||
let okMsg = "Sent Successfully.";
|
let okMsg = "Sent Successfully.";
|
||||||
try {
|
try {
|
||||||
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
|
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
|
||||||
// If heartbeatJSON is null, assume we're testing.
|
// If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing.
|
||||||
if (heartbeatJSON == null) {
|
if (heartbeatJSON == null) {
|
||||||
let mattermostTestData = {
|
let mattermostTestData = {
|
||||||
username: mattermostUserName,
|
username: mattermostUserName,
|
||||||
@ -27,97 +27,79 @@ class Mattermost extends NotificationProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mattermostIconEmoji = notification.mattermosticonemo;
|
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||||
const mattermostIconUrl = notification.mattermosticonurl;
|
let mattermostIconEmojiOnline = "";
|
||||||
|
let mattermostIconEmojiOffline = "";
|
||||||
|
|
||||||
if (heartbeatJSON["status"] === DOWN) {
|
if (mattermostIconEmoji && typeof mattermostIconEmoji === "string") {
|
||||||
let mattermostdowndata = {
|
const emojiArray = mattermostIconEmoji.split(" ");
|
||||||
username: mattermostUserName,
|
if (emojiArray.length >= 2) {
|
||||||
text: "Uptime Kuma Alert",
|
mattermostIconEmojiOnline = emojiArray[0];
|
||||||
channel: mattermostChannel,
|
mattermostIconEmojiOffline = emojiArray[1];
|
||||||
icon_emoji: mattermostIconEmoji,
|
}
|
||||||
icon_url: mattermostIconUrl,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
fallback:
|
|
||||||
"Your " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went down.",
|
|
||||||
color: "#FF0000",
|
|
||||||
title:
|
|
||||||
"❌ " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went down. ❌",
|
|
||||||
title_link: monitorJSON["url"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: false,
|
|
||||||
title: "Error",
|
|
||||||
value: heartbeatJSON["msg"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await axios.post(
|
|
||||||
notification.mattermostWebhookUrl,
|
|
||||||
mattermostdowndata
|
|
||||||
);
|
|
||||||
return okMsg;
|
|
||||||
} else if (heartbeatJSON["status"] === UP) {
|
|
||||||
let mattermostupdata = {
|
|
||||||
username: mattermostUserName,
|
|
||||||
text: "Uptime Kuma Alert",
|
|
||||||
channel: mattermostChannel,
|
|
||||||
icon_emoji: mattermostIconEmoji,
|
|
||||||
icon_url: mattermostIconUrl,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
fallback:
|
|
||||||
"Your " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went up!",
|
|
||||||
color: "#32CD32",
|
|
||||||
title:
|
|
||||||
"✅ " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went up! ✅",
|
|
||||||
title_link: monitorJSON["url"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: false,
|
|
||||||
title: "Ping",
|
|
||||||
value: heartbeatJSON["ping"] + "ms",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await axios.post(
|
|
||||||
notification.mattermostWebhookUrl,
|
|
||||||
mattermostupdata
|
|
||||||
);
|
|
||||||
return okMsg;
|
|
||||||
}
|
}
|
||||||
|
const mattermostIconUrl = notification.mattermosticonurl;
|
||||||
|
let iconEmoji = mattermostIconEmoji;
|
||||||
|
let statusField = {
|
||||||
|
short: false,
|
||||||
|
title: "Error",
|
||||||
|
value: heartbeatJSON.msg,
|
||||||
|
};
|
||||||
|
let statusText = "unknown";
|
||||||
|
let color = "#000000";
|
||||||
|
if (heartbeatJSON.status === DOWN) {
|
||||||
|
iconEmoji = mattermostIconEmojiOffline || mattermostIconEmoji;
|
||||||
|
statusField = {
|
||||||
|
short: false,
|
||||||
|
title: "Error",
|
||||||
|
value: heartbeatJSON.msg,
|
||||||
|
};
|
||||||
|
statusText = "down.";
|
||||||
|
color = "#FF0000";
|
||||||
|
} else if (heartbeatJSON.status === UP) {
|
||||||
|
iconEmoji = mattermostIconEmojiOnline || mattermostIconEmoji;
|
||||||
|
statusField = {
|
||||||
|
short: false,
|
||||||
|
title: "Ping",
|
||||||
|
value: heartbeatJSON.ping + "ms",
|
||||||
|
};
|
||||||
|
statusText = "up!";
|
||||||
|
color = "#32CD32";
|
||||||
|
}
|
||||||
|
|
||||||
|
let mattermostdata = {
|
||||||
|
username: monitorJSON.name + " " + mattermostUserName,
|
||||||
|
channel: mattermostChannel,
|
||||||
|
icon_emoji: iconEmoji,
|
||||||
|
icon_url: mattermostIconUrl,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
fallback:
|
||||||
|
"Your " +
|
||||||
|
monitorJSON.name +
|
||||||
|
" service went " +
|
||||||
|
statusText,
|
||||||
|
color: color,
|
||||||
|
title:
|
||||||
|
monitorJSON.name +
|
||||||
|
" service went " +
|
||||||
|
statusText,
|
||||||
|
title_link: monitorJSON.url,
|
||||||
|
fields: [
|
||||||
|
statusField,
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Time (UTC)",
|
||||||
|
value: heartbeatJSON.time,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
await axios.post(
|
||||||
|
notification.mattermostWebhookUrl,
|
||||||
|
mattermostdata
|
||||||
|
);
|
||||||
|
return okMsg;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.throwGeneralAxiosError(error);
|
this.throwGeneralAxiosError(error);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const NotificationProvider = require("./notification-provider");
|
const NotificationProvider = require("./notification-provider");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
class Ntfy extends NotificationProvider {
|
class Ntfy extends NotificationProvider {
|
||||||
|
|
||||||
@ -18,11 +19,45 @@ class Ntfy extends NotificationProvider {
|
|||||||
"Authorization": "Bearer " + notification.ntfyaccesstoken,
|
"Authorization": "Bearer " + notification.ntfyaccesstoken,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing.
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let ntfyTestData = {
|
||||||
|
"topic": notification.ntfytopic,
|
||||||
|
"title": (monitorJSON?.name || notification.ntfytopic) + " [Uptime-Kuma]",
|
||||||
|
"message": msg,
|
||||||
|
"priority": notification.ntfyPriority,
|
||||||
|
"tags": [ "test_tube" ],
|
||||||
|
};
|
||||||
|
await axios.post(`${notification.ntfyserverurl}`, ntfyTestData, { headers: headers });
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
let tags = [];
|
||||||
|
let status = "unknown";
|
||||||
|
let priority = notification.ntfyPriority || 4;
|
||||||
|
if ("status" in heartbeatJSON) {
|
||||||
|
if (heartbeatJSON.status === DOWN) {
|
||||||
|
tags = [ "red_circle" ];
|
||||||
|
status = "Down";
|
||||||
|
// if priority is not 5, increase priority for down alerts
|
||||||
|
priority = priority === 5 ? priority : priority + 1;
|
||||||
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
|
tags = [ "green_circle" ];
|
||||||
|
status = "Up";
|
||||||
|
}
|
||||||
|
}
|
||||||
let data = {
|
let data = {
|
||||||
"topic": notification.ntfytopic,
|
"topic": notification.ntfytopic,
|
||||||
"message": msg,
|
"message": heartbeatJSON.msg,
|
||||||
"priority": notification.ntfyPriority || 4,
|
"priority": priority,
|
||||||
"title": "Uptime-Kuma",
|
"title": monitorJSON.name + " " + status + " [Uptime-Kuma]",
|
||||||
|
"tags": tags,
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"action": "view",
|
||||||
|
"label": "Open " + monitorJSON.name,
|
||||||
|
"url": monitorJSON.url,
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (notification.ntfyIcon) {
|
if (notification.ntfyIcon) {
|
||||||
|
@ -90,7 +90,7 @@ export function hostNameRegexPattern(mqtt = false) {
|
|||||||
// Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
|
// Source: https://digitalfortress.tech/tips/top-15-commonly-used-regex/
|
||||||
const ipRegexPattern = `((^${mqtt ? mqttSchemeRegexPattern : ""}((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$)|(^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$))`;
|
const ipRegexPattern = `((^${mqtt ? mqttSchemeRegexPattern : ""}((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$)|(^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?$))`;
|
||||||
// Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
|
// Source: https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
|
||||||
const hostNameRegexPattern = `^${mqtt ? mqttSchemeRegexPattern : ""}([a-zA-Z0-9])?(([a-zA-Z0-9_]|[a-zA-Z0-9_][a-zA-Z0-9\\-_]*[a-zA-Z0-9_])\\.)*([A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9\\-_]*[A-Za-z0-9_])$`;
|
const hostNameRegexPattern = `^${mqtt ? mqttSchemeRegexPattern : ""}([a-zA-Z0-9])?(([a-zA-Z0-9_]|[a-zA-Z0-9_][a-zA-Z0-9\\-_]*[a-zA-Z0-9_])\\.)*([A-Za-z0-9_]|[A-Za-z0-9_][A-Za-z0-9\\-_]*[A-Za-z0-9_])(\\.)?$`;
|
||||||
|
|
||||||
return `${ipRegexPattern}|${hostNameRegexPattern}`;
|
return `${ipRegexPattern}|${hostNameRegexPattern}`;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user