diff --git a/package.json b/package.json index 4f7da681..1411168d 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "start-server": "node server/server.js", "start-server-dev": "cross-env NODE_ENV=development node server/server.js", "build": "vite build --config ./config/vite.config.js", - "test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test", + "test": "node test/prepare-test-server.js && npm run jest-backend", "test-with-build": "npm run build && npm test", - "jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js", + "jest-backend": "cross-env TEST_BACKEND=1 jest --runInBand --detectOpenHandles --forceExit --config=./config/jest-backend.config.js", "tsc": "tsc", "vite-preview-dist": "vite preview --host --config ./config/vite.config.js", "build-docker": "npm run build && npm run build-docker-debian && npm run build-docker-alpine", diff --git a/server/notification-providers/freemobile.js b/server/notification-providers/freemobile.js new file mode 100644 index 00000000..919150fa --- /dev/null +++ b/server/notification-providers/freemobile.js @@ -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; diff --git a/server/notification.js b/server/notification.js index 7a4b4f29..aed92e5d 100644 --- a/server/notification.js +++ b/server/notification.js @@ -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"); @@ -63,6 +64,7 @@ class Notification { new DingDing(), new Discord(), new Feishu(), + new FreeMobile(), new GoogleChat(), new Gorush(), new Gotify(), diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 98de65a4..6e77e1fd 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -138,7 +138,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 { diff --git a/src/components/notifications/FreeMobile.vue b/src/components/notifications/FreeMobile.vue new file mode 100644 index 00000000..852d9ae2 --- /dev/null +++ b/src/components/notifications/FreeMobile.vue @@ -0,0 +1,12 @@ + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 319a7922..bca4a510 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -7,6 +7,7 @@ import ClickSendSMS from "./ClickSendSMS.vue"; import DingDing from "./DingDing.vue"; import Discord from "./Discord.vue"; import Feishu from "./Feishu.vue"; +import FreeMobile from "./FreeMobile.vue"; import GoogleChat from "./GoogleChat.vue"; import Gorush from "./Gorush.vue"; import Gotify from "./Gotify.vue"; @@ -56,6 +57,7 @@ const NotificationFormList = { "DingDing": DingDing, "discord": Discord, "Feishu": Feishu, + "FreeMobile": FreeMobile, "GoogleChat": GoogleChat, "gorush": Gorush, "gotify": Gotify, diff --git a/test/backend.spec.js b/test/backend.spec.js index 6deb2853..5b9fa92c 100644 --- a/test/backend.spec.js +++ b/test/backend.spec.js @@ -1,7 +1,11 @@ -const { genSecret, DOWN } = require("../src/util"); +const { genSecret, DOWN, log} = require("../src/util"); const utilServerRewire = require("../server/util-server"); const Discord = require("../server/notification-providers/discord"); const axios = require("axios"); +const { UptimeKumaServer } = require("../server/uptime-kuma-server"); +const Database = require("../server/database"); +const {Settings} = require("../server/settings"); +const fs = require("fs"); jest.mock("axios"); @@ -225,3 +229,80 @@ describe("The function filterAndJoin", () => { expect(result).toBe(""); }); }); + +describe("Test uptimeKumaServer.getClientIP()", () => { + it("should able to get a correct client IP", async () => { + Database.init({ + "data-dir": "./data/test" + }); + + if (! fs.existsSync(Database.path)) { + log.info("server", "Copying Database"); + fs.copyFileSync(Database.templatePath, Database.path); + } + + await Database.connect(true); + await Database.patch(); + + const fakeSocket = { + client: { + conn: { + remoteAddress: "192.168.10.10", + request: { + headers: { + } + } + } + } + } + const server = Object.create(UptimeKumaServer.prototype); + let ip = await server.getClientIP(fakeSocket); + + await Settings.set("trustProxy", false); + expect(await Settings.get("trustProxy")).toBe(false); + expect(ip).toBe("192.168.10.10"); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "10.10.10.10"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("192.168.10.10"); + + fakeSocket.client.conn.request.headers["x-real-ip"] = "20.20.20.20"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("192.168.10.10"); + + await Settings.set("trustProxy", true); + expect(await Settings.get("trustProxy")).toBe(true); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "10.10.10.10"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("10.10.10.10"); + + // x-real-ip + delete fakeSocket.client.conn.request.headers["x-forwarded-for"]; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("20.20.20.20"); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "2001:db8:85a3:8d3:1319:8a2e:370:7348"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("2001:db8:85a3:8d3:1319:8a2e:370:7348"); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "203.0.113.195"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("203.0.113.195"); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("203.0.113.195"); + + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "203.0.113.195,2001:db8:85a3:8d3:1319:8a2e:370:7348,150.172.238.178"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("203.0.113.195"); + + // Elements are comma-separated, with optional whitespace surrounding the commas. + fakeSocket.client.conn.request.headers["x-forwarded-for"] = "203.0.113.195 , 2001:db8:85a3:8d3:1319:8a2e:370:7348,150.172.238.178"; + ip = await server.getClientIP(fakeSocket); + expect(ip).toBe("203.0.113.195"); + + await Database.close(); + }, 120000); +});