Merge remote-tracking branch 'origin/master' into karelkryda_master

# Conflicts:
#	server/model/monitor.js
#	server/model/status_page.js
#	src/languages/en.js
This commit is contained in:
Louis Lam
2022-10-09 19:26:00 +08:00
65 changed files with 1443 additions and 2112 deletions

View File

@@ -75,7 +75,7 @@ class DockerHost {
if (dockerHost.dockerType === "socket") {
options.socketPath = dockerHost.dockerDaemon;
} else if (dockerHost.dockerType === "tcp") {
options.baseURL = dockerHost.dockerDaemon;
options.baseURL = DockerHost.patchDockerURL(dockerHost.dockerDaemon);
}
let res = await axios.request(options);
@@ -99,6 +99,18 @@ class DockerHost {
}
}
/**
* Since axios 0.27.X, it does not accept `tcp://` protocol.
* Change it to `http://` on the fly in order to fix it. (https://github.com/louislam/uptime-kuma/issues/2165)
*/
static patchDockerURL(url) {
if (typeof url === "string") {
// Replace the first occurrence only with g
return url.replace(/tcp:\/\//g, "http://");
}
return url;
}
}
module.exports = {

View File

@@ -13,6 +13,7 @@ const version = require("../../package.json").version;
const apicache = require("../modules/apicache");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent");
const { DockerHost } = require("../docker");
const Maintenance = require("./maintenance");
/**
@@ -501,7 +502,7 @@ class Monitor extends BeanModel {
if (dockerHost._dockerType === "socket") {
options.socketPath = dockerHost._dockerDaemon;
} else if (dockerHost._dockerType === "tcp") {
options.baseURL = dockerHost._dockerDaemon;
options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon);
}
log.debug(`[${this.name}] Axios Request`);

View File

@@ -2,6 +2,7 @@ const { BeanModel } = require("redbean-node/dist/bean-model");
const { R } = require("redbean-node");
const cheerio = require("cheerio");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const jsesc = require("jsesc");
const Maintenance = require("./maintenance");
class StatusPage extends BeanModel {
@@ -57,13 +58,19 @@ class StatusPage extends BeanModel {
head.append(`<meta property="og:description" content="${description155}" />`);
// Preload data
const json = JSON.stringify(await StatusPage.getStatusPageData(statusPage));
head.append(`
<script>
window.preloadData = ${json}
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
const escapedJSONObject = jsesc(JSON.stringify(await StatusPage.getStatusPageData(statusPage)), {
"isScriptContext": true
});
const script = $(`
<script id="preload-data" data-json="{}">
window.preloadData = ${escapedJSONObject};
</script>
`);
head.append(script);
// manifest.json
$("link[rel=manifest]").attr("href", `/api/status-page/${statusPage.slug}/manifest.json`);

View File

@@ -0,0 +1,24 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class FreeMobile extends NotificationProvider {
name = "FreeMobile";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
await axios.post(`https://smsapi.free-mobile.fr/sendmsg?msg=${encodeURIComponent(msg.replace("🔴", "⛔️"))}`, {
"user": notification.freemobileUser,
"pass": notification.freemobilePass,
});
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = FreeMobile;

View File

@@ -8,12 +8,19 @@ class Ntfy extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
await axios.post(`${notification.ntfyserverurl}`, {
let headers = {};
if (notification.ntfyusername) {
headers = {
"Authorization": "Basic " + Buffer.from(notification.ntfyusername + ":" + notification.ntfypassword).toString("base64"),
};
}
let data = {
"topic": notification.ntfytopic,
"message": msg,
"priority": notification.ntfyPriority || 4,
"title": "Uptime-Kuma",
});
};
await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers });
return okMsg;

View File

@@ -10,7 +10,7 @@ class Octopush extends NotificationProvider {
try {
// Default - V2
if (notification.octopushVersion === 2 || !notification.octopushVersion) {
if (notification.octopushVersion === "2" || !notification.octopushVersion) {
let config = {
headers: {
"api-key": notification.octopushAPIKey,
@@ -31,7 +31,7 @@ class Octopush extends NotificationProvider {
"sender": notification.octopushSenderName
};
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config);
} else if (notification.octopushVersion === 1) {
} else if (notification.octopushVersion === "1") {
let data = {
"user_login": notification.octopushDMLogin,
"api_key": notification.octopushDMAPIKey,
@@ -49,7 +49,15 @@ class Octopush extends NotificationProvider {
},
params: data
};
await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config);
// V1 API returns 200 even on error so we must check
// response data
let response = await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config);
if ("error_code" in response.data) {
if (response.data.error_code !== "000") {
this.throwGeneralAxiosError(`Octopush error ${JSON.stringify(response.data)}`);
}
}
} else {
throw new Error("Unknown Octopush version!");
}

View File

@@ -0,0 +1,36 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class ServerChan extends NotificationProvider {
name = "ServerChan";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
await axios.post(`https://sctapi.ftqq.com/${notification.serverChanSendKey}.send`, {
"title": this.checkStatus(heartbeatJSON, monitorJSON),
"desp": msg,
});
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
checkStatus(heartbeatJSON, monitorJSON) {
let title = "UptimeKuma Message";
if (heartbeatJSON != null && heartbeatJSON["status"] === UP) {
title = "UptimeKuma Monitor Up " + monitorJSON["name"];
}
if (heartbeatJSON != null && heartbeatJSON["status"] === DOWN) {
title = "UptimeKuma Monitor Down " + monitorJSON["name"];
}
return title;
}
}
module.exports = ServerChan;

View File

@@ -0,0 +1,76 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN } = require("../../src/util");
class Squadcast extends NotificationProvider {
name = "squadcast";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let config = {};
let data = {
message: msg,
description: "",
tags: {},
heartbeat: heartbeatJSON,
source: "uptime-kuma"
};
if (heartbeatJSON !== null) {
data.description = heartbeatJSON["msg"];
data.event_id = heartbeatJSON["monitorID"];
if (heartbeatJSON["status"] === DOWN) {
data.message = `${monitorJSON["name"]} is DOWN`;
data.status = "trigger";
} else {
data.message = `${monitorJSON["name"]} is UP`;
data.status = "resolve";
}
let address;
switch (monitorJSON["type"]) {
case "ping":
address = monitorJSON["hostname"];
break;
case "port":
case "dns":
case "steam":
address = monitorJSON["hostname"];
if (monitorJSON["port"]) {
address += ":" + monitorJSON["port"];
}
break;
default:
address = monitorJSON["url"];
break;
}
data.tags["AlertAddress"] = address;
monitorJSON["tags"].forEach(tag => {
data.tags[tag["name"]] = {
value: tag["value"]
};
if (tag["color"] !== null) {
data.tags[tag["name"]]["color"] = tag["color"];
}
});
}
await axios.post(notification.squadcastWebhookURL, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Squadcast;

View File

@@ -63,7 +63,7 @@ class Teams extends NotificationProvider {
});
}
if (monitorUrl) {
if (monitorUrl && monitorUrl !== "https://") {
facts.push({
name: "URL",
value: monitorUrl,
@@ -127,13 +127,17 @@ class Teams extends NotificationProvider {
let url;
if (monitorJSON["type"] === "port") {
url = monitorJSON["hostname"];
if (monitorJSON["port"]) {
url += ":" + monitorJSON["port"];
}
} else {
url = monitorJSON["url"];
switch (monitorJSON["type"]) {
case "http":
case "keywork":
url = monitorJSON["url"];
break;
case "docker":
url = monitorJSON["docker_host"];
break;
default:
url = monitorJSON["hostname"];
break;
}
const payload = this._notificationPayloadFactory({

View File

@@ -9,6 +9,7 @@ const ClickSendSMS = require("./notification-providers/clicksendsms");
const DingDing = require("./notification-providers/dingding");
const Discord = require("./notification-providers/discord");
const Feishu = require("./notification-providers/feishu");
const FreeMobile = require("./notification-providers/freemobile");
const GoogleChat = require("./notification-providers/google-chat");
const Gorush = require("./notification-providers/gorush");
const Gotify = require("./notification-providers/gotify");
@@ -32,6 +33,7 @@ const SerwerSMS = require("./notification-providers/serwersms");
const Signal = require("./notification-providers/signal");
const Slack = require("./notification-providers/slack");
const SMTP = require("./notification-providers/smtp");
const Squadcast = require("./notification-providers/squadcast");
const Stackfield = require("./notification-providers/stackfield");
const Teams = require("./notification-providers/teams");
const TechulusPush = require("./notification-providers/techulus-push");
@@ -40,6 +42,7 @@ const Webhook = require("./notification-providers/webhook");
const WeCom = require("./notification-providers/wecom");
const GoAlert = require("./notification-providers/goalert");
const SMSManager = require("./notification-providers/smsmanager");
const ServerChan = require("./notification-providers/serverchan");
class Notification {
@@ -61,6 +64,7 @@ class Notification {
new DingDing(),
new Discord(),
new Feishu(),
new FreeMobile(),
new GoogleChat(),
new Gorush(),
new Gotify(),
@@ -80,11 +84,13 @@ class Notification {
new Pushover(),
new Pushy(),
new RocketChat(),
new ServerChan(),
new SerwerSMS(),
new Signal(),
new SMSManager(),
new Slack(),
new SMTP(),
new Squadcast(),
new Stackfield(),
new Teams(),
new TechulusPush(),

View File

@@ -105,7 +105,7 @@ Ping.prototype.send = function (callback) {
let _exited;
let _errored;
this._ping = spawn(this._bin, this._args); // spawn the binary
this._ping = spawn(this._bin, this._args, { windowsHide: true }); // spawn the binary
this._ping.on("error", function (err) { // handle binary errors
_errored = true;

View File

@@ -56,7 +56,7 @@ module.exports.dockerSocketHandler = (socket) => {
let amount = await DockerHost.testDockerHost(dockerHost);
let msg;
if (amount > 1) {
if (amount >= 1) {
msg = "Connected Successfully. Amount of containers: " + amount;
} else {
msg = "Connected Successfully, but there are no containers?";

View File

@@ -175,7 +175,9 @@ class UptimeKumaServer {
}
if (await Settings.get("trustProxy")) {
return socket.client.conn.request.headers["x-forwarded-for"]
const forwardedFor = socket.client.conn.request.headers["x-forwarded-for"];
return (typeof forwardedFor === "string" ? forwardedFor.split(",")[0].trim() : null)
|| socket.client.conn.request.headers["x-real-ip"]
|| clientIP.replace(/^.*:/, "");
} else {

View File

@@ -558,7 +558,7 @@ exports.doubleCheckPassword = async (socket, currentPassword) => {
exports.startUnitTest = async () => {
console.log("Starting unit test...");
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
const child = childProcess.spawn(npm, [ "run", "jest" ]);
const child = childProcess.spawn(npm, [ "run", "jest-backend" ]);
child.stdout.on("data", (data) => {
console.log(data.toString());