mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-18 01:16:54 +08:00
Compare commits
20 Commits
2.0.0-beta
...
1.23.X-to-
Author | SHA1 | Date | |
---|---|---|---|
|
4d16575599 | ||
|
5bb329fa0e | ||
|
09dedc07fb | ||
|
6cfae01a0d | ||
|
c0fe669cd8 | ||
|
cdb8ad321d | ||
|
4228dd0a29 | ||
|
8a432ac937 | ||
|
778363a948 | ||
|
6899603eb7 | ||
|
13ea190298 | ||
|
a7407a1b65 | ||
|
5bcde56a0f | ||
|
5864c6dd88 | ||
|
595b35fb15 | ||
|
0254e72177 | ||
|
06a272c119 | ||
|
93cf63cb06 | ||
|
32dc76a085 | ||
|
c6d6061a9f |
7
db/knex_migrations/2024-10-31-0000-fix-snmp-monitor.js
Normal file
7
db/knex_migrations/2024-10-31-0000-fix-snmp-monitor.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
exports.up = function (knex) {
|
||||||
|
return knex("monitor").whereNull("json_path_operator").update("json_path_operator", "==");
|
||||||
|
};
|
||||||
|
exports.down = function (knex) {
|
||||||
|
// changing the json_path_operator back to null for all "==" is not possible anymore
|
||||||
|
// we have lost the context which fields have been set explicitely in >= v2.0 and which would need to be reverted
|
||||||
|
};
|
@@ -5,7 +5,7 @@ const util = require("../../src/util");
|
|||||||
|
|
||||||
util.polyfill();
|
util.polyfill();
|
||||||
|
|
||||||
const version = process.env.VERSION;
|
const version = process.env.RELEASE_BETA_VERSION;
|
||||||
|
|
||||||
console.log("Beta Version: " + version);
|
console.log("Beta Version: " + version);
|
||||||
|
|
||||||
|
@@ -6,14 +6,13 @@ import {
|
|||||||
checkDocker,
|
checkDocker,
|
||||||
checkTagExists,
|
checkTagExists,
|
||||||
checkVersionFormat,
|
checkVersionFormat,
|
||||||
dryRun,
|
getRepoNames,
|
||||||
getRepoName,
|
|
||||||
pressAnyKey,
|
pressAnyKey,
|
||||||
execSync, uploadArtifacts,
|
execSync, uploadArtifacts,
|
||||||
} from "./lib.mjs";
|
} from "./lib.mjs";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
const repoName = getRepoName();
|
const repoNames = getRepoNames();
|
||||||
const version = process.env.RELEASE_BETA_VERSION;
|
const version = process.env.RELEASE_BETA_VERSION;
|
||||||
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ if (semverIdentifier[0] !== "beta") {
|
|||||||
checkDocker();
|
checkDocker();
|
||||||
|
|
||||||
// Check if the tag exists
|
// Check if the tag exists
|
||||||
await checkTagExists(repoName, version);
|
await checkTagExists(repoNames, version);
|
||||||
|
|
||||||
// node extra/beta/update-version.js
|
// node extra/beta/update-version.js
|
||||||
execSync("node ./extra/beta/update-version.js");
|
execSync("node ./extra/beta/update-version.js");
|
||||||
@@ -48,18 +47,18 @@ execSync("node ./extra/beta/update-version.js");
|
|||||||
buildDist();
|
buildDist();
|
||||||
|
|
||||||
// Build slim image (rootless)
|
// Build slim image (rootless)
|
||||||
buildImage(repoName, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
buildImage(repoNames, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||||
|
|
||||||
// Build full image (rootless)
|
// Build full image (rootless)
|
||||||
buildImage(repoName, [ "beta-rootless", ver(version, "rootless") ], "rootless");
|
buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless");
|
||||||
|
|
||||||
// Build slim image
|
// Build slim image
|
||||||
buildImage(repoName, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
buildImage(repoNames, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||||
|
|
||||||
// Build full image
|
// Build full image
|
||||||
buildImage(repoName, [ "beta", version ], "release");
|
buildImage(repoNames, [ "beta", version ], "release");
|
||||||
|
|
||||||
await pressAnyKey();
|
await pressAnyKey();
|
||||||
|
|
||||||
// npm run upload-artifacts
|
// npm run upload-artifacts
|
||||||
uploadArtifacts();
|
uploadArtifacts(version, githubToken);
|
||||||
|
@@ -6,11 +6,11 @@ import {
|
|||||||
checkDocker,
|
checkDocker,
|
||||||
checkTagExists,
|
checkTagExists,
|
||||||
checkVersionFormat,
|
checkVersionFormat,
|
||||||
getRepoName,
|
getRepoNames,
|
||||||
pressAnyKey, execSync, uploadArtifacts
|
pressAnyKey, execSync, uploadArtifacts
|
||||||
} from "./lib.mjs";
|
} from "./lib.mjs";
|
||||||
|
|
||||||
const repoName = getRepoName();
|
const repoNames = getRepoNames();
|
||||||
const version = process.env.RELEASE_VERSION;
|
const version = process.env.RELEASE_VERSION;
|
||||||
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ checkVersionFormat(version);
|
|||||||
checkDocker();
|
checkDocker();
|
||||||
|
|
||||||
// Check if the tag exists
|
// Check if the tag exists
|
||||||
await checkTagExists(repoName, version);
|
await checkTagExists(repoNames, version);
|
||||||
|
|
||||||
// node extra/beta/update-version.js
|
// node extra/beta/update-version.js
|
||||||
execSync("node extra/update-version.js");
|
execSync("node extra/update-version.js");
|
||||||
@@ -37,21 +37,21 @@ execSync("node extra/update-version.js");
|
|||||||
buildDist();
|
buildDist();
|
||||||
|
|
||||||
// Build slim image (rootless)
|
// Build slim image (rootless)
|
||||||
buildImage(repoName, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
buildImage(repoNames, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||||
|
|
||||||
// Build full image (rootless)
|
// Build full image (rootless)
|
||||||
buildImage(repoName, [ "2-rootless", ver(version, "rootless") ], "rootless");
|
buildImage(repoNames, [ "2-rootless", ver(version, "rootless") ], "rootless");
|
||||||
|
|
||||||
// Build slim image
|
// Build slim image
|
||||||
buildImage(repoName, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
buildImage(repoNames, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim");
|
||||||
|
|
||||||
// Build full image
|
// Build full image
|
||||||
buildImage(repoName, [ "next", "2", version ], "release");
|
buildImage(repoNames, [ "next", "2", version ], "release");
|
||||||
|
|
||||||
await pressAnyKey();
|
await pressAnyKey();
|
||||||
|
|
||||||
// npm run upload-artifacts
|
// npm run upload-artifacts
|
||||||
uploadArtifacts();
|
uploadArtifacts(version, githubToken);
|
||||||
|
|
||||||
// node extra/update-wiki-version.js
|
// node extra/update-wiki-version.js
|
||||||
execSync("node extra/update-wiki-version.js");
|
execSync("node extra/update-wiki-version.js");
|
||||||
|
@@ -24,8 +24,15 @@ export function checkDocker() {
|
|||||||
/**
|
/**
|
||||||
* Get Docker Hub repository name
|
* Get Docker Hub repository name
|
||||||
*/
|
*/
|
||||||
export function getRepoName() {
|
export function getRepoNames() {
|
||||||
return process.env.RELEASE_REPO_NAME || "louislam/uptime-kuma";
|
if (process.env.RELEASE_REPO_NAMES) {
|
||||||
|
// Split by comma
|
||||||
|
return process.env.RELEASE_REPO_NAMES.split(",").map((name) => name.trim());
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
"louislam/uptime-kuma",
|
||||||
|
"ghcr.io/louislam/uptime-kuma",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +49,7 @@ export function buildDist() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build docker image and push to Docker Hub
|
* Build docker image and push to Docker Hub
|
||||||
* @param {string} repoName Docker Hub repository name
|
* @param {string[]} repoNames Docker Hub repository names
|
||||||
* @param {string[]} tags Docker image tags
|
* @param {string[]} tags Docker image tags
|
||||||
* @param {string} target Dockerfile's target name
|
* @param {string} target Dockerfile's target name
|
||||||
* @param {string} buildArgs Docker build args
|
* @param {string} buildArgs Docker build args
|
||||||
@@ -50,7 +57,7 @@ export function buildDist() {
|
|||||||
* @param {string} platform Build platform
|
* @param {string} platform Build platform
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function buildImage(repoName, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") {
|
export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") {
|
||||||
let args = [
|
let args = [
|
||||||
"buildx",
|
"buildx",
|
||||||
"build",
|
"build",
|
||||||
@@ -60,9 +67,11 @@ export function buildImage(repoName, tags, target, buildArgs = "", dockerfile =
|
|||||||
platform,
|
platform,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Add tags
|
for (let repoName of repoNames) {
|
||||||
for (let tag of tags) {
|
// Add tags
|
||||||
args.push("-t", `${repoName}:${tag}`);
|
for (let tag of tags) {
|
||||||
|
args.push("-t", `${repoName}:${tag}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
@@ -171,10 +180,43 @@ export function ver(version, identifier) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload artifacts to GitHub
|
* Upload artifacts to GitHub
|
||||||
|
* docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain
|
||||||
|
* @param {string} version Version
|
||||||
|
* @param {string} githubToken GitHub token
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function uploadArtifacts() {
|
export function uploadArtifacts(version, githubToken) {
|
||||||
execSync("npm run upload-artifacts");
|
let args = [
|
||||||
|
"buildx",
|
||||||
|
"build",
|
||||||
|
"-f",
|
||||||
|
"docker/dockerfile",
|
||||||
|
"--platform",
|
||||||
|
"linux/amd64",
|
||||||
|
"-t",
|
||||||
|
"louislam/uptime-kuma:upload-artifact",
|
||||||
|
"--build-arg",
|
||||||
|
`VERSION=${version}`,
|
||||||
|
"--build-arg",
|
||||||
|
"GITHUB_TOKEN",
|
||||||
|
"--target",
|
||||||
|
"upload-artifact",
|
||||||
|
".",
|
||||||
|
"--progress",
|
||||||
|
"plain",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!dryRun) {
|
||||||
|
childProcess.spawnSync("docker", args, {
|
||||||
|
stdio: "inherit",
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
GITHUB_TOKEN: githubToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log(`[DRY RUN] docker ${args.join(" ")}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { buildDist, buildImage, checkDocker, getRepoName } from "./lib.mjs";
|
import { buildDist, buildImage, checkDocker, getRepoNames } from "./lib.mjs";
|
||||||
|
|
||||||
// Docker Hub repository name
|
// Docker Hub repository name
|
||||||
const repoName = getRepoName();
|
const repoNames = getRepoNames();
|
||||||
|
|
||||||
// Check if docker is running
|
// Check if docker is running
|
||||||
checkDocker();
|
checkDocker();
|
||||||
@@ -10,7 +10,7 @@ checkDocker();
|
|||||||
buildDist();
|
buildDist();
|
||||||
|
|
||||||
// Build full image (rootless)
|
// Build full image (rootless)
|
||||||
buildImage(repoName, [ "nightly2-rootless" ], "nightly-rootless");
|
buildImage(repoNames, [ "nightly2-rootless" ], "nightly-rootless");
|
||||||
|
|
||||||
// Build full image
|
// Build full image
|
||||||
buildImage(repoName, [ "nightly2" ], "nightly");
|
buildImage(repoNames, [ "nightly2" ], "nightly");
|
||||||
|
6
extra/release/upload-artifacts-beta.mjs
Normal file
6
extra/release/upload-artifacts-beta.mjs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { uploadArtifacts } from "./lib.mjs";
|
||||||
|
|
||||||
|
const version = process.env.RELEASE_BETA_VERSION;
|
||||||
|
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||||
|
|
||||||
|
uploadArtifacts(version, githubToken);
|
6
extra/release/upload-artifacts.mjs
Normal file
6
extra/release/upload-artifacts.mjs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { uploadArtifacts } from "./lib.mjs";
|
||||||
|
|
||||||
|
const version = process.env.RELEASE_VERSION;
|
||||||
|
const githubToken = process.env.RELEASE_GITHUB_TOKEN;
|
||||||
|
|
||||||
|
uploadArtifacts(version, githubToken);
|
@@ -5,7 +5,7 @@ const util = require("../src/util");
|
|||||||
|
|
||||||
util.polyfill();
|
util.polyfill();
|
||||||
|
|
||||||
const newVersion = process.env.VERSION;
|
const newVersion = process.env.RELEASE_VERSION;
|
||||||
|
|
||||||
console.log("New Version: " + newVersion);
|
console.log("New Version: " + newVersion);
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
const childProcess = require("child_process");
|
const childProcess = require("child_process");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
const newVersion = process.env.VERSION;
|
const newVersion = process.env.RELEASE_VERSION;
|
||||||
|
|
||||||
if (!newVersion) {
|
if (!newVersion) {
|
||||||
console.log("Missing version");
|
console.log("Missing version");
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "2.0.0-dev",
|
"version": "2.0.0-beta.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -39,7 +39,8 @@
|
|||||||
"build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push",
|
"build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push",
|
||||||
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
|
"build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .",
|
||||||
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
|
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
|
||||||
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
|
"upload-artifacts": "node extra/release/upload-artifacts.mjs",
|
||||||
|
"upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs",
|
||||||
"setup": "git checkout 1.23.15 && npm ci --production && npm run download-dist",
|
"setup": "git checkout 1.23.15 && npm ci --production && npm run download-dist",
|
||||||
"download-dist": "node extra/download-dist.js",
|
"download-dist": "node extra/download-dist.js",
|
||||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||||
|
@@ -296,7 +296,7 @@ class Database {
|
|||||||
client: "mysql2",
|
client: "mysql2",
|
||||||
connection: {
|
connection: {
|
||||||
socketPath: embeddedMariaDB.socketPath,
|
socketPath: embeddedMariaDB.socketPath,
|
||||||
user: "node",
|
user: embeddedMariaDB.username,
|
||||||
database: "kuma",
|
database: "kuma",
|
||||||
timezone: "Z",
|
timezone: "Z",
|
||||||
typeCast: function (field, next) {
|
typeCast: function (field, next) {
|
||||||
|
@@ -14,9 +14,15 @@ class EmbeddedMariaDB {
|
|||||||
|
|
||||||
mariadbDataDir = "/app/data/mariadb";
|
mariadbDataDir = "/app/data/mariadb";
|
||||||
|
|
||||||
runDir = "/app/data/run/mariadb";
|
runDir = "/app/data/run";
|
||||||
|
|
||||||
socketPath = this.runDir + "/mysqld.sock";
|
socketPath = this.runDir + "/mariadb.sock";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username to connect to the MariaDB
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
username = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {ChildProcessWithoutNullStreams}
|
* @type {ChildProcessWithoutNullStreams}
|
||||||
@@ -46,16 +52,42 @@ class EmbeddedMariaDB {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the embedded MariaDB
|
* Start the embedded MariaDB
|
||||||
|
* @throws {Error} If the current user is not "node" or "root"
|
||||||
* @returns {Promise<void>|void} A promise that resolves when the MariaDB is started or void if it is already started
|
* @returns {Promise<void>|void} A promise that resolves when the MariaDB is started or void if it is already started
|
||||||
*/
|
*/
|
||||||
start() {
|
start() {
|
||||||
|
// Check if the current user is "node" or "root"
|
||||||
|
this.username = require("os").userInfo().username;
|
||||||
|
if (this.username !== "node" && this.username !== "root") {
|
||||||
|
throw new Error("Embedded Mariadb supports only 'node' or 'root' user, but the current user is: " + this.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initDB();
|
||||||
|
|
||||||
|
this.startChildProcess();
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let interval = setInterval(() => {
|
||||||
|
if (this.started) {
|
||||||
|
clearInterval(interval);
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
log.info("mariadb", "Waiting for Embedded MariaDB to start...");
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the child process
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
startChildProcess() {
|
||||||
if (this.childProcess) {
|
if (this.childProcess) {
|
||||||
log.info("mariadb", "Already started");
|
log.info("mariadb", "Already started");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initDB();
|
|
||||||
|
|
||||||
this.running = true;
|
this.running = true;
|
||||||
log.info("mariadb", "Starting Embedded MariaDB");
|
log.info("mariadb", "Starting Embedded MariaDB");
|
||||||
this.childProcess = childProcess.spawn(this.exec, [
|
this.childProcess = childProcess.spawn(this.exec, [
|
||||||
@@ -63,6 +95,8 @@ class EmbeddedMariaDB {
|
|||||||
"--datadir=" + this.mariadbDataDir,
|
"--datadir=" + this.mariadbDataDir,
|
||||||
`--socket=${this.socketPath}`,
|
`--socket=${this.socketPath}`,
|
||||||
`--pid-file=${this.runDir}/mysqld.pid`,
|
`--pid-file=${this.runDir}/mysqld.pid`,
|
||||||
|
// Don't add the following option, the mariadb will not report message to the console, which affects initDBAfterStarted()
|
||||||
|
// "--log-error=" + `${this.mariadbDataDir}/mariadb-error.log`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.childProcess.on("close", (code) => {
|
this.childProcess.on("close", (code) => {
|
||||||
@@ -72,8 +106,8 @@ class EmbeddedMariaDB {
|
|||||||
log.info("mariadb", "Stopped Embedded MariaDB: " + code);
|
log.info("mariadb", "Stopped Embedded MariaDB: " + code);
|
||||||
|
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
log.info("mariadb", "Try to restart Embedded MariaDB as it is not stopped by user");
|
log.error("mariadb", "Try to restart Embedded MariaDB as it is not stopped by user");
|
||||||
this.start();
|
this.startChildProcess();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -86,7 +120,7 @@ class EmbeddedMariaDB {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let handler = (data) => {
|
let handler = (data) => {
|
||||||
log.debug("mariadb", data.toString("utf-8"));
|
log.info("mariadb", data.toString("utf-8"));
|
||||||
if (data.toString("utf-8").includes("ready for connections")) {
|
if (data.toString("utf-8").includes("ready for connections")) {
|
||||||
this.initDBAfterStarted();
|
this.initDBAfterStarted();
|
||||||
}
|
}
|
||||||
@@ -94,17 +128,6 @@ class EmbeddedMariaDB {
|
|||||||
|
|
||||||
this.childProcess.stdout.on("data", handler);
|
this.childProcess.stdout.on("data", handler);
|
||||||
this.childProcess.stderr.on("data", handler);
|
this.childProcess.stderr.on("data", handler);
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
let interval = setInterval(() => {
|
|
||||||
if (this.started) {
|
|
||||||
clearInterval(interval);
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
log.info("mariadb", "Waiting for Embedded MariaDB to start...");
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,9 +152,11 @@ class EmbeddedMariaDB {
|
|||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = childProcess.spawnSync("mysql_install_db", [
|
let result = childProcess.spawnSync("mariadb-install-db", [
|
||||||
"--user=node",
|
"--user=node",
|
||||||
"--ldata=" + this.mariadbDataDir,
|
"--auth-root-socket-user=node",
|
||||||
|
"--datadir=" + this.mariadbDataDir,
|
||||||
|
"--auth-root-authentication-method=socket",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (result.status !== 0) {
|
if (result.status !== 0) {
|
||||||
@@ -143,6 +168,17 @@ class EmbeddedMariaDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the owner of the mariadb directory, and change it if necessary
|
||||||
|
let stat = fs.statSync(this.mariadbDataDir);
|
||||||
|
if (stat.uid !== 1000 || stat.gid !== 1000) {
|
||||||
|
fs.chownSync(this.mariadbDataDir, 1000, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the permission of the mariadb directory, and change it if it is not 755
|
||||||
|
if (stat.mode !== 0o755) {
|
||||||
|
fs.chmodSync(this.mariadbDataDir, 0o755);
|
||||||
|
}
|
||||||
|
|
||||||
if (!fs.existsSync(this.runDir)) {
|
if (!fs.existsSync(this.runDir)) {
|
||||||
log.info("mariadb", `Embedded MariaDB: ${this.runDir} is not found, create one now.`);
|
log.info("mariadb", `Embedded MariaDB: ${this.runDir} is not found, create one now.`);
|
||||||
fs.mkdirSync(this.runDir, {
|
fs.mkdirSync(this.runDir, {
|
||||||
@@ -150,6 +186,13 @@ class EmbeddedMariaDB {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stat = fs.statSync(this.runDir);
|
||||||
|
if (stat.uid !== 1000 || stat.gid !== 1000) {
|
||||||
|
fs.chownSync(this.runDir, 1000, 1000);
|
||||||
|
}
|
||||||
|
if (stat.mode !== 0o755) {
|
||||||
|
fs.chmodSync(this.runDir, 0o755);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,7 +202,7 @@ class EmbeddedMariaDB {
|
|||||||
async initDBAfterStarted() {
|
async initDBAfterStarted() {
|
||||||
const connection = mysql.createConnection({
|
const connection = mysql.createConnection({
|
||||||
socketPath: this.socketPath,
|
socketPath: this.socketPath,
|
||||||
user: "node",
|
user: this.username,
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = await connection.execute("CREATE DATABASE IF NOT EXISTS `kuma`");
|
let result = await connection.execute("CREATE DATABASE IF NOT EXISTS `kuma`");
|
||||||
|
@@ -1522,7 +1522,7 @@ class Monitor extends BeanModel {
|
|||||||
*/
|
*/
|
||||||
static async getMonitorTag(monitorIDs) {
|
static async getMonitorTag(monitorIDs) {
|
||||||
return await R.getAll(`
|
return await R.getAll(`
|
||||||
SELECT monitor_tag.monitor_id, monitor_tag.tag_id, tag.name, tag.color
|
SELECT monitor_tag.monitor_id, monitor_tag.tag_id, monitor_tag.value, tag.name, tag.color
|
||||||
FROM monitor_tag
|
FROM monitor_tag
|
||||||
JOIN tag ON monitor_tag.tag_id = tag.id
|
JOIN tag ON monitor_tag.tag_id = tag.id
|
||||||
WHERE monitor_tag.monitor_id IN (${monitorIDs.map((_) => "?").join(",")})
|
WHERE monitor_tag.monitor_id IN (${monitorIDs.map((_) => "?").join(",")})
|
||||||
@@ -1567,6 +1567,8 @@ class Monitor extends BeanModel {
|
|||||||
}
|
}
|
||||||
tagsMap.get(row.monitor_id).push({
|
tagsMap.get(row.monitor_id).push({
|
||||||
tag_id: row.tag_id,
|
tag_id: row.tag_id,
|
||||||
|
monitor_id: row.monitor_id,
|
||||||
|
value: row.value,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
color: row.color
|
color: row.color
|
||||||
});
|
});
|
||||||
|
@@ -240,6 +240,14 @@ class RealBrowserMonitorType extends MonitorType {
|
|||||||
const context = await browser.newContext();
|
const context = await browser.newContext();
|
||||||
const page = await context.newPage();
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
// Prevent Local File Inclusion
|
||||||
|
// Accept only http:// and https://
|
||||||
|
// https://github.com/louislam/uptime-kuma/security/advisories/GHSA-2qgm-m29m-cj2h
|
||||||
|
let url = new URL(monitor.url);
|
||||||
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
||||||
|
throw new Error("Invalid url protocol, only http and https are allowed.");
|
||||||
|
}
|
||||||
|
|
||||||
const res = await page.goto(monitor.url, {
|
const res = await page.goto(monitor.url, {
|
||||||
waitUntil: "networkidle",
|
waitUntil: "networkidle",
|
||||||
timeout: monitor.interval * 1000 * 0.8,
|
timeout: monitor.interval * 1000 * 0.8,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
const NotificationProvider = require("./notification-provider");
|
const NotificationProvider = require("./notification-provider");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { setSettings, setting } = require("../util-server");
|
const { setSettings, setting } = require("../util-server");
|
||||||
const { getMonitorRelativeURL, UP } = require("../../src/util");
|
const { getMonitorRelativeURL, UP, log } = require("../../src/util");
|
||||||
|
|
||||||
class Slack extends NotificationProvider {
|
class Slack extends NotificationProvider {
|
||||||
name = "slack";
|
name = "slack";
|
||||||
@@ -50,15 +50,20 @@ class Slack extends NotificationProvider {
|
|||||||
|
|
||||||
const address = this.extractAddress(monitorJSON);
|
const address = this.extractAddress(monitorJSON);
|
||||||
if (address) {
|
if (address) {
|
||||||
actions.push({
|
try {
|
||||||
"type": "button",
|
actions.push({
|
||||||
"text": {
|
"type": "button",
|
||||||
"type": "plain_text",
|
"text": {
|
||||||
"text": "Visit site",
|
"type": "plain_text",
|
||||||
},
|
"text": "Visit site",
|
||||||
"value": "Site",
|
},
|
||||||
"url": address,
|
"value": "Site",
|
||||||
});
|
"url": new URL(address),
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
log.debug("slack", `Failed to parse address ${address} as URL`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
@@ -15,11 +15,13 @@ const server = UptimeKumaServer.getInstance();
|
|||||||
|
|
||||||
router.get("/status/:slug", cache("5 minutes"), async (request, response) => {
|
router.get("/status/:slug", cache("5 minutes"), async (request, response) => {
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/status/:slug/rss", cache("5 minutes"), async (request, response) => {
|
router.get("/status/:slug/rss", cache("5 minutes"), async (request, response) => {
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
await StatusPage.handleStatusPageRSSResponse(response, slug);
|
await StatusPage.handleStatusPageRSSResponse(response, slug);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ router.get("/status-page", cache("5 minutes"), async (request, response) => {
|
|||||||
router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
|
router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get Status Page
|
// Get Status Page
|
||||||
@@ -69,6 +72,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||||||
let uptimeList = {};
|
let uptimeList = {};
|
||||||
|
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
let statusPageID = await StatusPage.slugToID(slug);
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
let monitorIDList = await R.getCol(`
|
let monitorIDList = await R.getCol(`
|
||||||
@@ -111,6 +115,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||||||
router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async (request, response) => {
|
router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get Status Page
|
// Get Status Page
|
||||||
@@ -145,7 +150,8 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
|
|||||||
// overall status-page status badge
|
// overall status-page status badge
|
||||||
router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, response) => {
|
router.get("/api/status-page/:slug/badge", cache("5 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
const slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
slug = slug.toLowerCase();
|
||||||
const statusPageID = await StatusPage.slugToID(slug);
|
const statusPageID = await StatusPage.slugToID(slug);
|
||||||
const {
|
const {
|
||||||
label,
|
label,
|
||||||
|
@@ -220,13 +220,17 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||||||
|
|
||||||
// Delete groups that are not in the list
|
// Delete groups that are not in the list
|
||||||
log.debug("socket", "Delete groups that are not in the list");
|
log.debug("socket", "Delete groups that are not in the list");
|
||||||
const slots = groupIDList.map(() => "?").join(",");
|
if (groupIDList.length === 0) {
|
||||||
|
await R.exec("DELETE FROM `group` WHERE status_page_id = ?", [ statusPage.id ]);
|
||||||
|
} else {
|
||||||
|
const slots = groupIDList.map(() => "?").join(",");
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
...groupIDList,
|
...groupIDList,
|
||||||
statusPage.id
|
statusPage.id
|
||||||
];
|
];
|
||||||
await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots}) AND status_page_id = ?`, data);
|
await R.exec(`DELETE FROM \`group\` WHERE id NOT IN (${slots}) AND status_page_id = ?`, data);
|
||||||
|
}
|
||||||
|
|
||||||
const server = UptimeKumaServer.getInstance();
|
const server = UptimeKumaServer.getInstance();
|
||||||
|
|
||||||
@@ -288,6 +292,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||||||
ok: true,
|
ok: true,
|
||||||
msg: "successAdded",
|
msg: "successAdded",
|
||||||
msgi18n: true,
|
msgi18n: true,
|
||||||
|
slug: slug
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -619,7 +619,7 @@ $shadow-box-padding: 20px;
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
margin-left: -$shadow-box-padding;
|
margin-left: -$shadow-box-padding;
|
||||||
margin-right: -$shadow-box-padding;
|
margin-right: -$shadow-box-padding;
|
||||||
z-index: 100;
|
z-index: 10;
|
||||||
background-color: rgba(white, 0.2);
|
background-color: rgba(white, 0.2);
|
||||||
backdrop-filter: blur(2px);
|
backdrop-filter: blur(2px);
|
||||||
border-radius: 0 0 10px 10px;
|
border-radius: 0 0 10px 10px;
|
||||||
|
@@ -5,20 +5,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-from-email" class="form-label">{{ $t("From Email") }}</label>
|
<label for="sendgrid-from-email" class="form-label">{{ $t("From Email") }}</label>
|
||||||
<input id="sendgrid-from-email" v-model="$parent.notification.sendgridFromEmail" type="email" class="form-control" required>
|
<input id="sendgrid-from-email" v-model="$parent.notification.sendgridFromEmail" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-to-email" class="form-label">{{ $t("To Email") }}</label>
|
<label for="sendgrid-to-email" class="form-label">{{ $t("To Email") }}</label>
|
||||||
<input id="sendgrid-to-email" v-model="$parent.notification.sendgridToEmail" type="email" class="form-control" required>
|
<input id="sendgrid-to-email" v-model="$parent.notification.sendgridToEmail" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-cc-email" class="form-label">{{ $t("smtpCC") }}</label>
|
<label for="sendgrid-cc-email" class="form-label">{{ $t("smtpCC") }}</label>
|
||||||
<input id="sendgrid-cc-email" v-model="$parent.notification.sendgridCcEmail" type="email" class="form-control">
|
<input id="sendgrid-cc-email" v-model="$parent.notification.sendgridCcEmail" type="text" class="form-control">
|
||||||
<div class="form-text">{{ $t("Separate multiple email addresses with commas") }}</div>
|
<div class="form-text">{{ $t("Separate multiple email addresses with commas") }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="sendgrid-bcc-email" class="form-label">{{ $t("smtpBCC") }}</label>
|
<label for="sendgrid-bcc-email" class="form-label">{{ $t("smtpBCC") }}</label>
|
||||||
<input id="sendgrid-bcc-email" v-model="$parent.notification.sendgridBccEmail" type="email" class="form-control">
|
<input id="sendgrid-bcc-email" v-model="$parent.notification.sendgridBccEmail" type="text" class="form-control">
|
||||||
<small class="form-text text-muted">{{ $t("Separate multiple email addresses with commas") }}</small>
|
<small class="form-text text-muted">{{ $t("Separate multiple email addresses with commas") }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@@ -16,14 +16,11 @@
|
|||||||
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
|
<label for="slug" class="form-label">{{ $t("Slug") }}</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span id="basic-addon3" class="input-group-text">/status/</span>
|
<span id="basic-addon3" class="input-group-text">/status/</span>
|
||||||
<input id="slug" v-model="slug" type="text" class="form-control" required data-testid="slug-input">
|
<input id="slug" v-model="slug" type="text" class="form-control" autocapitalize="none" required data-testid="slug-input">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<ul>
|
<ul>
|
||||||
<li>{{ $t("Accept characters:") }} <mark>a-z</mark> <mark>0-9</mark> <mark>-</mark></li>
|
<li>{{ $t("Accept characters:") }} <mark>a-z</mark> <mark>0-9</mark> <mark>-</mark></li>
|
||||||
<i18n-t tag="li" keypath="startOrEndWithOnly">
|
|
||||||
<mark>a-z</mark> <mark>0-9</mark>
|
|
||||||
</i18n-t>
|
|
||||||
<li>{{ $t("No consecutive dashes") }} <mark>--</mark></li>
|
<li>{{ $t("No consecutive dashes") }} <mark>--</mark></li>
|
||||||
<i18n-t tag="li" keypath="statusPageSpecialSlugDesc">
|
<i18n-t tag="li" keypath="statusPageSpecialSlugDesc">
|
||||||
<mark class="me-1">default</mark>
|
<mark class="me-1">default</mark>
|
||||||
@@ -65,7 +62,7 @@ export default {
|
|||||||
this.processing = false;
|
this.processing = false;
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
location.href = "/status/" + this.slug + "?edit";
|
location.href = "/status/" + res.slug + "?edit";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (res.msg.includes("UNIQUE constraint")) {
|
if (res.msg.includes("UNIQUE constraint")) {
|
||||||
@@ -85,4 +82,8 @@ export default {
|
|||||||
.shadow-box {
|
.shadow-box {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#slug {
|
||||||
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1065,7 +1065,7 @@ import { hostNameRegexPattern } from "../util-frontend";
|
|||||||
import HiddenInput from "../components/HiddenInput.vue";
|
import HiddenInput from "../components/HiddenInput.vue";
|
||||||
import EditMonitorConditions from "../components/EditMonitorConditions.vue";
|
import EditMonitorConditions from "../components/EditMonitorConditions.vue";
|
||||||
|
|
||||||
const toast = useToast;
|
const toast = useToast();
|
||||||
|
|
||||||
const pushTokenLength = 32;
|
const pushTokenLength = 32;
|
||||||
|
|
||||||
@@ -1443,11 +1443,14 @@ message HealthCheckResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.monitor.type === "snmp") {
|
// Set a default timeout if the monitor type has changed or if it's a new monitor
|
||||||
|
if (oldType || this.isAdd) {
|
||||||
|
if (this.monitor.type === "snmp") {
|
||||||
// snmp is not expected to be executed via the internet => we can choose a lower default timeout
|
// snmp is not expected to be executed via the internet => we can choose a lower default timeout
|
||||||
this.monitor.timeout = 5;
|
this.monitor.timeout = 5;
|
||||||
} else {
|
} else {
|
||||||
this.monitor.timeout = 48;
|
this.monitor.timeout = 48;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default SNMP version
|
// Set default SNMP version
|
||||||
|
Reference in New Issue
Block a user