diff --git a/.dockerignore b/.dockerignore
index 3d92084d..539e9328 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -19,7 +19,6 @@ README.md
.eslint*
.stylelint*
/.github
-package-lock.json
yarn.lock
app.json
CODE_OF_CONDUCT.md
diff --git a/README.md b/README.md
index f0fa92d9..4ad1c555 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Uptime Kuma
-
+
+
diff --git a/db/patch-monitor-push_token.sql b/db/patch-monitor-push_token.sql
new file mode 100644
index 00000000..8c2e7a42
--- /dev/null
+++ b/db/patch-monitor-push_token.sql
@@ -0,0 +1,7 @@
+-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
+BEGIN TRANSACTION;
+
+ALTER TABLE monitor
+ ADD push_token VARCHAR(20) DEFAULT NULL;
+
+COMMIT;
diff --git a/docker/alpine-base.dockerfile b/docker/alpine-base.dockerfile
new file mode 100644
index 00000000..922fd252
--- /dev/null
+++ b/docker/alpine-base.dockerfile
@@ -0,0 +1,8 @@
+# DON'T UPDATE TO alpine3.13, 1.14, see #41.
+FROM node:14-alpine3.12
+WORKDIR /app
+
+# Install apprise, iputils for non-root ping, setpriv
+RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
+ pip3 --no-cache-dir install apprise && \
+ rm -rf /root/.cache
diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile
new file mode 100644
index 00000000..a4d70167
--- /dev/null
+++ b/docker/debian-base.dockerfile
@@ -0,0 +1,12 @@
+# DON'T UPDATE TO node:14-bullseye-slim, see #372.
+# If the image changed, the second stage image should be changed too
+FROM node:14-buster-slim
+WORKDIR /app
+
+# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv
+# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specific --no-install-recommends to skip them, make the base even smaller than alpine!
+RUN apt update && \
+ apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
+ sqlite3 iputils-ping util-linux dumb-init && \
+ pip3 --no-cache-dir install apprise && \
+ rm -rf /var/lib/apt/lists/*
diff --git a/dockerfile b/dockerfile
index e0616ba2..969d5ff3 100644
--- a/dockerfile
+++ b/dockerfile
@@ -1,6 +1,4 @@
-# DON'T UPDATE TO node:14-bullseye-slim, see #372.
-# If the image changed, the second stage image should be changed too
-FROM node:14-buster-slim AS build
+FROM louislam/uptime-kuma:base-debian AS build
WORKDIR /app
COPY . .
@@ -10,16 +8,9 @@ RUN npm install --legacy-peer-deps && \
chmod +x /app/extra/entrypoint.sh
-FROM node:14-buster-slim AS release
+FROM louislam/uptime-kuma:base-debian AS release
WORKDIR /app
-# Install Apprise, add sqlite3 cli for debugging in the future, iputils-ping for ping, util-linux for setpriv
-RUN apt update && \
- apt --yes install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
- sqlite3 iputils-ping util-linux dumb-init && \
- pip3 --no-cache-dir install apprise && \
- rm -rf /var/lib/apt/lists/*
-
# Copy app files from build layer
COPY --from=build /app /app
@@ -33,7 +24,7 @@ FROM release AS nightly
RUN npm run mark-as-nightly
# Upload the artifact to Github
-FROM node:14-buster-slim AS upload-artifact
+FROM louislam/uptime-kuma:base-debian AS upload-artifact
WORKDIR /
RUN apt update && \
apt --yes install curl file
@@ -41,17 +32,18 @@ RUN apt update && \
ARG GITHUB_TOKEN
ARG TARGETARCH
ARG PLATFORM=debian
-ARG VERSION=1.5.0
-
+ARG VERSION
+ARG FILE=$PLATFORM-$TARGETARCH-$VERSION.tar.gz
+ARG DIST=dist.tar.gz
COPY --from=build /app /app
+RUN chmod +x /app/extra/upload-github-release-asset.sh
-RUN FILE=uptime-kuma.tar.gz
-RUN tar -czf $FILE app
+# Full Build
+# RUN tar -zcvf $FILE app
+# RUN /app/extra/upload-github-release-asset.sh github_api_token=$GITHUB_TOKEN owner=louislam repo=uptime-kuma tag=$VERSION filename=$FILE
-RUN curl \
- -H "Authorization: token $GITHUB_TOKEN" \
- -H "Content-Type: $(file -b --mime-type $FILE)" \
- --data-binary @$FILE \
- "https://uploads.github.com/repos/louislam/uptime-kuma/releases/$VERSION/assets?name=$(basename $FILE)"
+# Dist only
+RUN cd /app && tar -zcvf $DIST dist
+RUN /app/extra/upload-github-release-asset.sh github_api_token=$GITHUB_TOKEN owner=louislam repo=uptime-kuma tag=$VERSION filename=$DIST
diff --git a/dockerfile-alpine b/dockerfile-alpine
index 07ae3079..178afcab 100644
--- a/dockerfile-alpine
+++ b/dockerfile-alpine
@@ -1,5 +1,4 @@
-# DON'T UPDATE TO alpine3.13, 1.14, see #41.
-FROM node:14-alpine3.12 AS build
+FROM louislam/uptime-kuma:base-alpine AS build
WORKDIR /app
COPY . .
@@ -9,14 +8,9 @@ RUN npm install --legacy-peer-deps && \
chmod +x /app/extra/entrypoint.sh
-FROM node:14-alpine3.12 AS release
+FROM louislam/uptime-kuma:base-alpine AS release
WORKDIR /app
-# Install apprise, iputils for non-root ping, setpriv
-RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
- pip3 --no-cache-dir install apprise && \
- rm -rf /root/.cache
-
# Copy app files from build layer
COPY --from=build /app /app
diff --git a/extra/upload-github-release-asset.sh b/extra/upload-github-release-asset.sh
new file mode 100644
index 00000000..206e3cd6
--- /dev/null
+++ b/extra/upload-github-release-asset.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+#
+# Author: Stefan Buck
+# License: MIT
+# https://gist.github.com/stefanbuck/ce788fee19ab6eb0b4447a85fc99f447
+#
+#
+# This script accepts the following parameters:
+#
+# * owner
+# * repo
+# * tag
+# * filename
+# * github_api_token
+#
+# Script to upload a release asset using the GitHub API v3.
+#
+# Example:
+#
+# upload-github-release-asset.sh github_api_token=TOKEN owner=stefanbuck repo=playground tag=v0.1.0 filename=./build.zip
+#
+
+# Check dependencies.
+set -e
+xargs=$(which gxargs || which xargs)
+
+# Validate settings.
+[ "$TRACE" ] && set -x
+
+CONFIG=$@
+
+for line in $CONFIG; do
+ eval "$line"
+done
+
+# Define variables.
+GH_API="https://api.github.com"
+GH_REPO="$GH_API/repos/$owner/$repo"
+GH_TAGS="$GH_REPO/releases/tags/$tag"
+AUTH="Authorization: token $github_api_token"
+WGET_ARGS="--content-disposition --auth-no-challenge --no-cookie"
+CURL_ARGS="-LJO#"
+
+if [[ "$tag" == 'LATEST' ]]; then
+ GH_TAGS="$GH_REPO/releases/latest"
+fi
+
+# Validate token.
+curl -o /dev/null -sH "$AUTH" $GH_REPO || { echo "Error: Invalid repo, token or network issue!"; exit 1; }
+
+# Read asset tags.
+response=$(curl -sH "$AUTH" $GH_TAGS)
+
+# Get ID of the asset based on given filename.
+eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
+[ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; }
+
+# Upload asset
+echo "Uploading asset... "
+
+# Construct url
+GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$id/assets?name=$(basename $filename)"
+
+curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $github_api_token" -H "Content-Type: application/octet-stream" $GH_ASSET
diff --git a/package-lock.json b/package-lock.json
index 88053f53..34615b9d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,75 +1,77 @@
{
"name": "uptime-kuma",
- "version": "1.7.2",
+ "version": "1.7.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "uptime-kuma",
- "version": "1.7.2",
+ "version": "1.7.3",
"license": "MIT",
"dependencies": {
- "@fortawesome/fontawesome-svg-core": "^1.2.36",
- "@fortawesome/free-regular-svg-icons": "^5.15.4",
- "@fortawesome/free-solid-svg-icons": "^5.15.4",
- "@fortawesome/vue-fontawesome": "^3.0.0-4",
- "@louislam/sqlite3": "^5.0.6",
- "@popperjs/core": "^2.10.1",
- "args-parser": "^1.3.0",
- "axios": "^0.21.4",
- "bcryptjs": "^2.4.3",
- "bootstrap": "^5.1.1",
- "chart.js": "^3.5.1",
- "chartjs-adapter-dayjs": "^1.0.0",
- "command-exists": "^1.2.9",
- "compare-versions": "^3.6.0",
- "dayjs": "^1.10.7",
- "express": "^4.17.1",
- "express-basic-auth": "^1.2.0",
- "form-data": "^4.0.0",
- "http-graceful-shutdown": "^3.1.4",
- "jsonwebtoken": "^8.5.1",
- "nodemailer": "^6.6.5",
- "notp": "^2.0.3",
- "password-hash": "^1.2.2",
- "prom-client": "^13.2.0",
- "prometheus-api-metrics": "^3.2.0",
- "qrcode": "^1.4.4",
+ "@fortawesome/fontawesome-svg-core": "~1.2.36",
+ "@fortawesome/free-regular-svg-icons": "~5.15.4",
+ "@fortawesome/free-solid-svg-icons": "~5.15.4",
+ "@fortawesome/vue-fontawesome": "~3.0.0-4",
+ "@louislam/sqlite3": "~5.0.6",
+ "@popperjs/core": "~2.10.1",
+ "args-parser": "~1.3.0",
+ "axios": "~0.21.4",
+ "bcryptjs": "~2.4.3",
+ "bootstrap": "~5.1.1",
+ "chart.js": "~3.5.1",
+ "chartjs-adapter-dayjs": "~1.0.0",
+ "command-exists": "~1.2.9",
+ "compare-versions": "~3.6.0",
+ "dayjs": "~1.10.7",
+ "express": "~4.17.1",
+ "express-basic-auth": "~1.2.0",
+ "form-data": "~4.0.0",
+ "http-graceful-shutdown": "~3.1.4",
+ "jsonwebtoken": "~8.5.1",
+ "nodemailer": "~6.6.5",
+ "notp": "~2.0.3",
+ "password-hash": "~1.2.2",
+ "postcss-rtlcss": "~3.4.1",
+ "postcss-scss": "~4.0.0",
+ "prom-client": "~13.2.0",
+ "prometheus-api-metrics": "~3.2.0",
+ "qrcode": "~1.4.4",
"redbean-node": "0.1.2",
- "socket.io": "^4.2.0",
- "socket.io-client": "^4.2.0",
- "tcp-ping": "^0.1.1",
- "thirty-two": "^1.0.2",
- "timezones-list": "^3.0.1",
- "v-pagination-3": "^0.1.6",
+ "socket.io": "~4.2.0",
+ "socket.io-client": "~4.2.0",
+ "tcp-ping": "~0.1.1",
+ "thirty-two": "~1.0.2",
+ "timezones-list": "~3.0.1",
+ "v-pagination-3": "~0.1.6",
"vue": "next",
- "vue-chart-3": "^0.5.8",
- "vue-confirm-dialog": "^1.0.2",
- "vue-contenteditable": "^3.0.4",
- "vue-i18n": "^9.1.7",
- "vue-image-crop-upload": "^3.0.3",
- "vue-multiselect": "^3.0.0-alpha.2",
- "vue-qrcode": "^1.0.0",
- "vue-router": "^4.0.11",
- "vue-toastification": "^2.0.0-rc.1",
- "vuedraggable": "^4.1.0"
+ "vue-chart-3": "~0.5.8",
+ "vue-confirm-dialog": "~1.0.2",
+ "vue-contenteditable": "~3.0.4",
+ "vue-i18n": "~9.1.7",
+ "vue-image-crop-upload": "~3.0.3",
+ "vue-multiselect": "~3.0.0-alpha.2",
+ "vue-qrcode": "~1.0.0",
+ "vue-router": "~4.0.11",
+ "vue-toastification": "~2.0.0-rc.1",
+ "vuedraggable": "~4.1.0"
},
"devDependencies": {
- "@babel/eslint-parser": "^7.15.7",
- "@types/bootstrap": "^5.1.6",
- "@vitejs/plugin-legacy": "^1.5.3",
- "@vitejs/plugin-vue": "^1.9.1",
- "@vue/compiler-sfc": "^3.2.16",
- "core-js": "^3.18.0",
- "cross-env": "^7.0.3",
- "dns2": "^2.0.1",
- "eslint": "^7.32.0",
- "eslint-plugin-vue": "^7.18.0",
- "sass": "^1.42.1",
- "stylelint": "^13.13.1",
- "stylelint-config-standard": "^22.0.0",
- "typescript": "^4.4.3",
- "vite": "2.5.*"
+ "@babel/eslint-parser": "~7.15.7",
+ "@types/bootstrap": "~5.1.6",
+ "@vitejs/plugin-legacy": "~1.5.3",
+ "@vitejs/plugin-vue": "~1.9.1",
+ "@vue/compiler-sfc": "~3.2.16",
+ "core-js": "~3.18.0",
+ "cross-env": "~7.0.3",
+ "dns2": "~2.0.1",
+ "eslint": "~7.32.0",
+ "eslint-plugin-vue": "~7.18.0",
+ "sass": "~1.42.1",
+ "stylelint": "~13.13.1",
+ "stylelint-config-standard": "~22.0.0",
+ "typescript": "~4.4.3",
+ "vite": "~2.5.10"
},
"engines": {
"node": "14.*"
@@ -1056,16 +1058,16 @@
"dev": true
},
"node_modules/@vitejs/plugin-legacy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.6.0.tgz",
- "integrity": "sha512-MrOT7DWJyln10Eobh38TL9Pg0yDjRec5ZlK0Opi+jZA/qniXgofvGJskOyvfbSKKmUkjLO2dUDLz2rIm2oIYtw==",
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.5.3.tgz",
+ "integrity": "sha512-/b2x6dU+BbdW7C7KWxh9kMrVzv1JlUi1ucPQpSzWUUUVJjihbG+GRlpqcvfQ0p/TnAKl2d/VecbTLByVJJHORg==",
"dev": true,
"dependencies": {
- "@babel/standalone": "^7.15.7",
- "core-js": "^3.18.1",
+ "@babel/standalone": "^7.14.9",
+ "core-js": "^3.16.0",
"magic-string": "^0.25.7",
"regenerator-runtime": "^0.13.9",
- "systemjs": "^6.10.3"
+ "systemjs": "^6.10.2"
},
"engines": {
"node": ">=12.0.0"
@@ -1280,7 +1282,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -1783,7 +1784,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -1942,7 +1942,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -1953,8 +1952,7 @@
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/colorette": {
"version": "1.2.1",
@@ -3345,7 +3343,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -4779,7 +4776,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -4930,6 +4926,20 @@
"integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
"dev": true
},
+ "node_modules/postcss-rtlcss": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-3.4.1.tgz",
+ "integrity": "sha512-4SOkC34IJ086dYjmqGCeIOqQe4JTDk+jwETvq1M/57+bQA6CXEWAjGtqifjcSH75nd0vfW7+hve0Ec4ZYHmMtA==",
+ "dependencies": {
+ "rtlcss": "^3.3.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
"node_modules/postcss-safe-parser": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
@@ -4987,32 +4997,18 @@
}
},
"node_modules/postcss-scss": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
- "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
- "dev": true,
- "dependencies": {
- "postcss": "^7.0.6"
- },
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.1.tgz",
+ "integrity": "sha512-7QghUu2l07OyVFT5LyvU/QJ1f2s8IL0mfToN69Yu533PgMZm2B1S6hYd4bao8tFq70r3P5MmAbKhVrZ4wOADxg==",
"engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/postcss-scss/node_modules/postcss": {
- "version": "7.0.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.38.tgz",
- "integrity": "sha512-wNrSHWjHDQJR/IZL5IKGxRtFgrYNaAA/UrkW2WqbtZO6uxSLMxMN+s2iqUMwnAWm3fMROlDYZB41dr0Mt7vBwQ==",
- "dev": true,
- "dependencies": {
- "nanocolors": "^0.2.2",
- "source-map": "^0.6.1"
- },
- "engines": {
- "node": ">=6.0.0"
+ "node": ">=12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.3.3"
}
},
"node_modules/postcss-selector-parser": {
@@ -5562,6 +5558,81 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/rtlcss": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.3.0.tgz",
+ "integrity": "sha512-XZ2KEatH2nU5yPlts1Wu8SGIuZ3ndN025HQX5MqtUCUiOn5WkCDbcpJ2VJWjpuFmM2cUTQ1xtH21fhMCSseI5A==",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "find-up": "^5.0.0",
+ "mkdirp": "^1.0.4",
+ "postcss": "^8.2.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "bin": {
+ "rtlcss": "bin/rtlcss.js"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.4"
+ }
+ },
+ "node_modules/rtlcss/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rtlcss/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rtlcss/node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rtlcss/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5972,7 +6043,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
"engines": {
"node": ">=8"
},
@@ -6120,6 +6190,18 @@
"url": "https://opencollective.com/postcss/"
}
},
+ "node_modules/stylelint/node_modules/postcss-scss": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
+ "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
+ "dev": true,
+ "dependencies": {
+ "postcss": "^7.0.6"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/stylelint/node_modules/resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
@@ -6173,7 +6255,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -7222,6 +7303,17 @@
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
},
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/zwitch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
@@ -8021,16 +8113,16 @@
"dev": true
},
"@vitejs/plugin-legacy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.6.0.tgz",
- "integrity": "sha512-MrOT7DWJyln10Eobh38TL9Pg0yDjRec5ZlK0Opi+jZA/qniXgofvGJskOyvfbSKKmUkjLO2dUDLz2rIm2oIYtw==",
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.5.3.tgz",
+ "integrity": "sha512-/b2x6dU+BbdW7C7KWxh9kMrVzv1JlUi1ucPQpSzWUUUVJjihbG+GRlpqcvfQ0p/TnAKl2d/VecbTLByVJJHORg==",
"dev": true,
"requires": {
- "@babel/standalone": "^7.15.7",
- "core-js": "^3.18.1",
+ "@babel/standalone": "^7.14.9",
+ "core-js": "^3.16.0",
"magic-string": "^0.25.7",
"regenerator-runtime": "^0.13.9",
- "systemjs": "^6.10.3"
+ "systemjs": "^6.10.2"
}
},
"@vitejs/plugin-vue": {
@@ -8207,7 +8299,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -8593,7 +8684,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -8707,7 +8797,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -8715,8 +8804,7 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"colorette": {
"version": "1.2.1",
@@ -9804,8 +9892,7 @@
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"has-unicode": {
"version": "2.0.1",
@@ -10853,8 +10940,7 @@
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
},
"path-is-absolute": {
"version": "1.0.1",
@@ -10962,6 +11048,14 @@
"integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
"dev": true
},
+ "postcss-rtlcss": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/postcss-rtlcss/-/postcss-rtlcss-3.4.1.tgz",
+ "integrity": "sha512-4SOkC34IJ086dYjmqGCeIOqQe4JTDk+jwETvq1M/57+bQA6CXEWAjGtqifjcSH75nd0vfW7+hve0Ec4ZYHmMtA==",
+ "requires": {
+ "rtlcss": "^3.3.0"
+ }
+ },
"postcss-safe-parser": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz",
@@ -11006,25 +11100,10 @@
}
},
"postcss-scss": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
- "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
- "dev": true,
- "requires": {
- "postcss": "^7.0.6"
- },
- "dependencies": {
- "postcss": {
- "version": "7.0.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.38.tgz",
- "integrity": "sha512-wNrSHWjHDQJR/IZL5IKGxRtFgrYNaAA/UrkW2WqbtZO6uxSLMxMN+s2iqUMwnAWm3fMROlDYZB41dr0Mt7vBwQ==",
- "dev": true,
- "requires": {
- "nanocolors": "^0.2.2",
- "source-map": "^0.6.1"
- }
- }
- }
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.1.tgz",
+ "integrity": "sha512-7QghUu2l07OyVFT5LyvU/QJ1f2s8IL0mfToN69Yu533PgMZm2B1S6hYd4bao8tFq70r3P5MmAbKhVrZ4wOADxg==",
+ "requires": {}
},
"postcss-selector-parser": {
"version": "6.0.6",
@@ -11444,6 +11523,53 @@
"fsevents": "~2.3.2"
}
},
+ "rtlcss": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.3.0.tgz",
+ "integrity": "sha512-XZ2KEatH2nU5yPlts1Wu8SGIuZ3ndN025HQX5MqtUCUiOn5WkCDbcpJ2VJWjpuFmM2cUTQ1xtH21fhMCSseI5A==",
+ "requires": {
+ "chalk": "^4.1.0",
+ "find-up": "^5.0.0",
+ "mkdirp": "^1.0.4",
+ "postcss": "^8.2.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ }
+ }
+ },
"run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -11770,8 +11896,7 @@
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
},
"style-search": {
"version": "0.1.0",
@@ -11869,6 +11994,15 @@
"source-map": "^0.6.1"
}
},
+ "postcss-scss": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz",
+ "integrity": "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==",
+ "dev": true,
+ "requires": {
+ "postcss": "^7.0.6"
+ }
+ },
"resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
@@ -11929,7 +12063,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -12706,6 +12839,11 @@
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
},
+ "yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
+ },
"zwitch": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
diff --git a/package.json b/package.json
index 87b30565..17bfe975 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,8 @@
"tsc": "tsc",
"vite-preview-dist": "vite preview --host",
"build-docker": "npm run build-docker-debian && npm run build-docker-alpine",
+ "build-docker-alpine-base": "docker buildx build -f docker/alpine-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-alpine . --push",
+ "build-docker-debian-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base-debian . --push",
"build-docker-alpine": "docker buildx build -f dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:alpine -t louislam/uptime-kuma:1-alpine -t louislam/uptime-kuma:1.7.3-alpine --target release . --push",
"build-docker-debian": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.7.3 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.7.3-debian --target release . --push",
"build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
@@ -44,66 +46,68 @@
"update-language-files": "cd extra/update-language-files && node index.js && eslint ../../src/languages/**.js --fix"
},
"dependencies": {
- "@fortawesome/fontawesome-svg-core": "^1.2.36",
- "@fortawesome/free-regular-svg-icons": "^5.15.4",
- "@fortawesome/free-solid-svg-icons": "^5.15.4",
- "@fortawesome/vue-fontawesome": "^3.0.0-4",
- "@louislam/sqlite3": "^5.0.6",
- "@popperjs/core": "^2.10.1",
- "args-parser": "^1.3.0",
- "axios": "^0.21.4",
- "bcryptjs": "^2.4.3",
- "bootstrap": "^5.1.1",
- "chart.js": "^3.5.1",
- "chartjs-adapter-dayjs": "^1.0.0",
- "command-exists": "^1.2.9",
- "compare-versions": "^3.6.0",
- "dayjs": "^1.10.7",
- "express": "^4.17.1",
- "express-basic-auth": "^1.2.0",
- "form-data": "^4.0.0",
- "http-graceful-shutdown": "^3.1.4",
- "jsonwebtoken": "^8.5.1",
- "nodemailer": "^6.6.5",
- "notp": "^2.0.3",
- "password-hash": "^1.2.2",
- "prom-client": "^13.2.0",
- "prometheus-api-metrics": "^3.2.0",
- "qrcode": "^1.4.4",
+ "@fortawesome/fontawesome-svg-core": "~1.2.36",
+ "@fortawesome/free-regular-svg-icons": "~5.15.4",
+ "@fortawesome/free-solid-svg-icons": "~5.15.4",
+ "@fortawesome/vue-fontawesome": "~3.0.0-4",
+ "@louislam/sqlite3": "~5.0.6",
+ "@popperjs/core": "~2.10.1",
+ "args-parser": "~1.3.0",
+ "axios": "~0.21.4",
+ "bcryptjs": "~2.4.3",
+ "bootstrap": "~5.1.1",
+ "chart.js": "~3.5.1",
+ "chartjs-adapter-dayjs": "~1.0.0",
+ "command-exists": "~1.2.9",
+ "compare-versions": "~3.6.0",
+ "dayjs": "~1.10.7",
+ "express": "~4.17.1",
+ "express-basic-auth": "~1.2.0",
+ "form-data": "~4.0.0",
+ "http-graceful-shutdown": "~3.1.4",
+ "jsonwebtoken": "~8.5.1",
+ "nodemailer": "~6.6.5",
+ "notp": "~2.0.3",
+ "password-hash": "~1.2.2",
+ "postcss-rtlcss": "~3.4.1",
+ "postcss-scss": "~4.0.0",
+ "prom-client": "~13.2.0",
+ "prometheus-api-metrics": "~3.2.0",
+ "qrcode": "~1.4.4",
"redbean-node": "0.1.2",
- "socket.io": "^4.2.0",
- "socket.io-client": "^4.2.0",
- "tcp-ping": "^0.1.1",
- "thirty-two": "^1.0.2",
- "timezones-list": "^3.0.1",
- "v-pagination-3": "^0.1.6",
+ "socket.io": "~4.2.0",
+ "socket.io-client": "~4.2.0",
+ "tcp-ping": "~0.1.1",
+ "thirty-two": "~1.0.2",
+ "timezones-list": "~3.0.1",
+ "v-pagination-3": "~0.1.6",
"vue": "next",
- "vue-chart-3": "^0.5.8",
- "vue-confirm-dialog": "^1.0.2",
- "vue-contenteditable": "^3.0.4",
- "vue-i18n": "^9.1.7",
- "vue-image-crop-upload": "^3.0.3",
- "vue-multiselect": "^3.0.0-alpha.2",
- "vue-qrcode": "^1.0.0",
- "vue-router": "^4.0.11",
- "vue-toastification": "^2.0.0-rc.1",
- "vuedraggable": "^4.1.0"
+ "vue-chart-3": "~0.5.8",
+ "vue-confirm-dialog": "~1.0.2",
+ "vue-contenteditable": "~3.0.4",
+ "vue-i18n": "~9.1.7",
+ "vue-image-crop-upload": "~3.0.3",
+ "vue-multiselect": "~3.0.0-alpha.2",
+ "vue-qrcode": "~1.0.0",
+ "vue-router": "~4.0.11",
+ "vue-toastification": "~2.0.0-rc.1",
+ "vuedraggable": "~4.1.0"
},
"devDependencies": {
- "@babel/eslint-parser": "^7.15.7",
- "@types/bootstrap": "^5.1.6",
- "@vitejs/plugin-legacy": "^1.5.3",
- "@vitejs/plugin-vue": "^1.9.1",
- "@vue/compiler-sfc": "^3.2.16",
- "core-js": "^3.18.0",
- "cross-env": "^7.0.3",
- "dns2": "^2.0.1",
- "eslint": "^7.32.0",
- "eslint-plugin-vue": "^7.18.0",
- "sass": "^1.42.1",
- "stylelint": "^13.13.1",
- "stylelint-config-standard": "^22.0.0",
- "typescript": "^4.4.3",
- "vite": "2.5.*"
+ "@babel/eslint-parser": "~7.15.7",
+ "@types/bootstrap": "~5.1.6",
+ "@vitejs/plugin-legacy": "~1.5.3",
+ "@vitejs/plugin-vue": "~1.9.1",
+ "@vue/compiler-sfc": "~3.2.16",
+ "core-js": "~3.18.0",
+ "cross-env": "~7.0.3",
+ "dns2": "~2.0.1",
+ "eslint": "~7.32.0",
+ "eslint-plugin-vue": "~7.18.0",
+ "sass": "~1.42.1",
+ "stylelint": "~13.13.1",
+ "stylelint-config-standard": "~22.0.0",
+ "typescript": "~4.4.3",
+ "vite": "~2.5.10"
}
}
diff --git a/server/database.js b/server/database.js
index 4cf1e393..47eca283 100644
--- a/server/database.js
+++ b/server/database.js
@@ -48,6 +48,7 @@ class Database {
"patch-add-retry-interval-monitor.sql": true,
"patch-incident-table.sql": true,
"patch-group-table.sql": true,
+ "patch-monitor-push_token.sql": true,
}
/**
diff --git a/server/model/monitor.js b/server/model/monitor.js
index a50baccf..c551fa7d 100644
--- a/server/model/monitor.js
+++ b/server/model/monitor.js
@@ -69,6 +69,7 @@ class Monitor extends BeanModel {
dns_resolve_type: this.dns_resolve_type,
dns_resolve_server: this.dns_resolve_server,
dns_last_result: this.dns_last_result,
+ pushToken: this.pushToken,
notificationIDList,
tags: tags,
};
@@ -236,6 +237,28 @@ class Monitor extends BeanModel {
bean.msg = dnsMessage;
bean.status = UP;
+ } else if (this.type === "push") { // Type: Push
+ const time = R.isoDateTime(dayjs.utc().subtract(this.interval, "second"));
+
+ let heartbeatCount = await R.count("heartbeat", " monitor_id = ? AND time > ? ", [
+ this.id,
+ time
+ ]);
+
+ debug("heartbeatCount" + heartbeatCount + " " + time);
+
+ if (heartbeatCount <= 0) {
+ throw new Error("No heartbeat in the time window");
+ } else {
+ // No need to insert successful heartbeat for push type, so end here
+ retries = 0;
+ this.heartbeatInterval = setTimeout(beat, this.interval * 1000);
+ return;
+ }
+
+ } else {
+ bean.msg = "Unknown Monitor Type";
+ bean.status = PENDING;
}
if (this.isUpsideDown()) {
@@ -263,6 +286,8 @@ class Monitor extends BeanModel {
}
}
+ let beatInterval = this.interval;
+
// * ? -> ANY STATUS = important [isFirstBeat]
// UP -> PENDING = not important
// * UP -> DOWN = important
@@ -312,8 +337,6 @@ class Monitor extends BeanModel {
bean.important = false;
}
- let beatInterval = this.interval;
-
if (bean.status === UP) {
console.info(`Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`);
} else if (bean.status === PENDING) {
@@ -339,7 +362,14 @@ class Monitor extends BeanModel {
};
- beat();
+ // Delay Push Type
+ if (this.type === "push") {
+ setTimeout(() => {
+ beat();
+ }, this.interval * 1000);
+ } else {
+ beat();
+ }
}
stop() {
diff --git a/server/routers/api-router.js b/server/routers/api-router.js
index b56efcb2..0da1fd70 100644
--- a/server/routers/api-router.js
+++ b/server/routers/api-router.js
@@ -4,15 +4,55 @@ const { R } = require("redbean-node");
const server = require("../server");
const apicache = require("../modules/apicache");
const Monitor = require("../model/monitor");
+const dayjs = require("dayjs");
+const { UP } = require("../../src/util");
let router = express.Router();
let cache = apicache.middleware;
+let io = server.io;
router.get("/api/entry-page", async (_, response) => {
allowDevAllOrigin(response);
response.json(server.entryPage);
});
+router.get("/api/push/:pushToken", async (request, response) => {
+ try {
+ let pushToken = request.params.pushToken;
+ let msg = request.query.msg || "OK";
+ let ping = request.query.ping;
+
+ let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [
+ pushToken
+ ]);
+
+ if (! monitor) {
+ throw new Error("Monitor not found or not active.");
+ }
+
+ let bean = R.dispense("heartbeat");
+ bean.monitor_id = monitor.id;
+ bean.time = R.isoDateTime(dayjs.utc());
+ bean.status = UP;
+ bean.msg = msg;
+ bean.ping = ping;
+
+ await R.store(bean);
+
+ io.to(monitor.user_id).emit("heartbeat", bean.toJSON());
+ Monitor.sendStats(io, monitor.id, monitor.user_id);
+
+ response.json({
+ ok: true,
+ });
+ } catch (e) {
+ response.json({
+ ok: false,
+ msg: e.message
+ });
+ }
+});
+
// Status Page Config
router.get("/api/status-page/config", async (_request, response) => {
allowDevAllOrigin(response);
diff --git a/server/server.js b/server/server.js
index ddd68695..0fbe8325 100644
--- a/server/server.js
+++ b/server/server.js
@@ -6,7 +6,7 @@ if (! process.env.NODE_ENV) {
console.log("Node Env: " + process.env.NODE_ENV);
-const { sleep, debug, TimeLogger, getRandomInt } = require("../src/util");
+const { sleep, debug, getRandomInt, genSecret } = require("../src/util");
console.log("Importing Node libraries");
const fs = require("fs");
@@ -37,7 +37,7 @@ console.log("Importing this project modules");
debug("Importing Monitor");
const Monitor = require("./model/monitor");
debug("Importing Settings");
-const { getSettings, setSettings, setting, initJWTSecret, genSecret, allowDevAllOrigin, checkLogin } = require("./util-server");
+const { getSettings, setSettings, setting, initJWTSecret, checkLogin } = require("./util-server");
debug("Importing Notification");
const { Notification } = require("./notification");
@@ -71,7 +71,7 @@ if (demoMode) {
console.log("==== Demo Mode ====");
}
-console.log("Creating express and socket.io instance")
+console.log("Creating express and socket.io instance");
const app = express();
let server;
@@ -303,6 +303,12 @@ exports.entryPage = "dashboard";
if (user.twofa_status == 0) {
let newSecret = await genSecret();
let encodedSecret = base32.encode(newSecret);
+
+ // Google authenticator doesn't like equal signs
+ // The fix is found at https://github.com/guyht/notp
+ // Related issue: https://github.com/louislam/uptime-kuma/issues/486
+ encodedSecret = encodedSecret.toString().replace(/=/g, "");
+
let uri = `otpauth://totp/Uptime%20Kuma:${user.username}?secret=${encodedSecret}`;
await R.exec("UPDATE `user` SET twofa_secret = ? WHERE id = ? ", [
@@ -511,6 +517,7 @@ exports.entryPage = "dashboard";
bean.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
bean.dns_resolve_type = monitor.dns_resolve_type;
bean.dns_resolve_server = monitor.dns_resolve_server;
+ bean.pushToken = monitor.pushToken;
await R.store(bean);
diff --git a/server/util-server.js b/server/util-server.js
index 4d2b6cbe..29e4b11f 100644
--- a/server/util-server.js
+++ b/server/util-server.js
@@ -272,16 +272,6 @@ exports.getTotalClientInRoom = (io, roomName) => {
}
};
-exports.genSecret = () => {
- let secret = "";
- let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- let charsLength = chars.length;
- for ( let i = 0; i < 64; i++ ) {
- secret += chars.charAt(Math.floor(Math.random() * charsLength));
- }
- return secret;
-};
-
exports.allowDevAllOrigin = (res) => {
if (process.env.NODE_ENV === "development") {
exports.allowAllOrigin(res);
diff --git a/src/App.vue b/src/App.vue
index a16d4208..099450d4 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,7 +1,12 @@
-
+
diff --git a/src/assets/app.scss b/src/assets/app.scss
index f4707df9..34a4560c 100644
--- a/src/assets/app.scss
+++ b/src/assets/app.scss
@@ -180,6 +180,11 @@ h2 {
border-color: $dark-border-color;
}
+ .form-control:disabled, .form-control[readonly] {
+ background-color: #232f3b;
+ opacity: 1;
+ }
+
.table-hover > tbody > tr:hover {
--bs-table-accent-bg: #070a10;
color: $dark-font-color;
@@ -405,3 +410,7 @@ h2 {
.vue-image-crop-upload .vicp-wrap {
border-radius: 10px !important;
}
+
+// Localization
+
+@import "localization.scss";
\ No newline at end of file
diff --git a/src/assets/localization.scss b/src/assets/localization.scss
new file mode 100644
index 00000000..f9a28d8a
--- /dev/null
+++ b/src/assets/localization.scss
@@ -0,0 +1,5 @@
+html[lang='fa'] {
+ #app {
+ font-family: 'IRANSans', 'Iranian Sans','B Nazanin', 'Tahoma', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji;
+ }
+}
\ No newline at end of file
diff --git a/src/components/CopyableInput.vue b/src/components/CopyableInput.vue
new file mode 100644
index 00000000..1fe89802
--- /dev/null
+++ b/src/components/CopyableInput.vue
@@ -0,0 +1,122 @@
+
+
+
+
+
diff --git a/src/components/Login.vue b/src/components/Login.vue
index ca36fdb9..8a20fbdb 100644
--- a/src/components/Login.vue
+++ b/src/components/Login.vue
@@ -52,7 +52,7 @@ export default {
token: "",
res: null,
tokenRequired: false,
- }
+ };
},
methods: {
submit() {
@@ -60,21 +60,20 @@ export default {
this.$root.login(this.username, this.password, this.token, (res) => {
this.processing = false;
- console.log(res)
+ console.log(res);
if (res.tokenRequired) {
this.tokenRequired = true;
} else {
this.res = res;
}
- })
+ });
},
},
-}
+};
-