Compare commits

..

149 Commits
1.0.0 ... 1.0.6

Author SHA1 Message Date
LouisLam
657acf748b update to 1.0.6 2021-07-20 20:04:54 +08:00
Louis Lam
71dd68bb6d Update README.md 2021-07-20 13:04:21 +08:00
Louis Lam
58d029445d Merge pull request #79 from Saibamen/remove_debug_spam
Remove debug spam
2021-07-19 23:12:33 +08:00
LouisLam
77af41bfff env default to production 2021-07-19 23:06:42 +08:00
Louis Lam
058032a26a Merge pull request #81 from Saibamen/use_NODE_ENV
Use `NODE_ENV` from Express and Socket.IO
2021-07-19 22:59:36 +08:00
Louis Lam
cbb9d3f91b set version for docker 2021-07-19 20:18:27 +08:00
Adam Stachowicz
5bd3184ebf Use connect_error event 2021-07-18 20:59:00 +02:00
Adam Stachowicz
59ebe134f1 Fix indentation 2021-07-18 20:46:45 +02:00
Adam Stachowicz
851ceef3d5 Use NODE_ENV from Express and Socket.IO 2021-07-18 20:21:17 +02:00
LouisLam
efd7608ba2 Merge remote-tracking branch 'origin/master' 2021-07-19 00:43:45 +08:00
LouisLam
05fdaf0c96 update package-lock.json 2021-07-19 00:43:25 +08:00
Louis Lam
01b0e82d52 Update README.md 2021-07-19 00:40:10 +08:00
Louis Lam
d2ccfd5366 Update README.md 2021-07-19 00:39:07 +08:00
Adam Stachowicz
7cba9ce231 Remove debug spam 2021-07-18 18:35:40 +02:00
Louis Lam
69e8c56e3e Update README.md 2021-07-19 00:34:48 +08:00
LouisLam
25c370c9ff Merge branch 'update_packages'
# Conflicts:
#	package-lock.json
#	package.json
2021-07-18 22:22:19 +08:00
LouisLam
9227ff6ea3 add nightly build for amd64 only 2021-07-18 22:21:34 +08:00
Louis Lam
f7bd67c413 Merge pull request #77 from Saibamen/fix_docker
Fix Docker build
2021-07-18 20:53:06 +08:00
LouisLam
9ca2444dab improve testing notification response 2021-07-18 20:49:46 +08:00
Adam Stachowicz
1d45a7606d Fix Docker build 2021-07-18 13:51:44 +02:00
Louis Lam
d6b9403f60 Merge pull request #76 from Saibamen/fix_remember_me
Fix multiple labels for `Remember me`
2021-07-18 19:28:48 +08:00
Louis Lam
92e5ddd97c Merge pull request #69 from Saibamen/dockerignore
Update .dockerignore
2021-07-18 19:27:43 +08:00
Louis Lam
23611e540c Merge pull request #70 from Saibamen/fix_npm_warnings
Fix NPM warnings
2021-07-18 19:27:00 +08:00
Adam Stachowicz
f9274557f3 Fix center 2021-07-18 13:22:39 +02:00
Adam Stachowicz
44b66cbd2e Fix Remember me label 2021-07-18 13:00:59 +02:00
LouisLam
66037e236c add apprise support 2021-07-18 18:51:58 +08:00
Adam Stachowicz
386c002fda Merge branch 'master' into fix_npm_warnings 2021-07-18 11:48:08 +02:00
Adam Stachowicz
7c1aab6a15 Merge branch 'master' into dockerignore 2021-07-18 11:47:53 +02:00
Adam Stachowicz
37884cfd08 Merge branch 'master' into update_packages 2021-07-18 11:47:08 +02:00
LouisLam
13c9244e3f fix apprise import issue and loose the healthcheck rule 2021-07-18 17:42:00 +08:00
Louis Lam
13b3a5be9c Merge pull request #68 from Saibamen/use_console_error
Improve printing to console
2021-07-18 14:55:30 +08:00
Louis Lam
2e31e780a1 Merge pull request #67 from Saibamen/lighthouse_improvements
[Lighthouse] Some improvements
2021-07-18 13:48:35 +08:00
Louis Lam
6a2b5f9dd8 Merge pull request #66 from Saibamen/resize_apple_icon
[Lighthouse] Resize apple icon to 192px
2021-07-18 13:47:50 +08:00
Louis Lam
16767dc042 Merge pull request #65 from Saibamen/robots
[Lighthouse] Add robots.txt
2021-07-18 13:47:39 +08:00
Louis Lam
fb3e000dc3 Merge pull request #63 from NiNiyas/docker-healthcheck
Docker Healthcheck
2021-07-18 13:47:25 +08:00
Louis Lam
6f3ea21864 Merge pull request #61 from NiNiyas/slack-enhancements
Slack Enhancements and aligns footer to center
2021-07-18 13:47:04 +08:00
Louis Lam
403137280e Merge pull request #62 from NiNiyas/pushover-support
Pushover support
2021-07-18 12:20:41 +08:00
Adam Stachowicz
9c248776e7 Update dependencies 2021-07-18 00:08:35 +02:00
Adam Stachowicz
309caa4279 Fix indentation 2021-07-17 23:57:48 +02:00
Adam Stachowicz
28b14ceb70 Fix NPM warnings 2021-07-17 23:45:36 +02:00
Adam Stachowicz
9f9c42c30b Update .dockerignore 2021-07-17 23:31:44 +02:00
Adam Stachowicz
2bff62cade Improve printing to console 2021-07-17 23:13:54 +02:00
Adam Stachowicz
bfb4a5bcd4 Add alt="Logo" 2021-07-17 22:56:54 +02:00
Adam Stachowicz
e87b78501b rel="noopener" for external link 2021-07-17 22:55:53 +02:00
Adam Stachowicz
637422494f Add description 2021-07-17 22:53:32 +02:00
Adam Stachowicz
db34484ff2 Add theme-color 2021-07-17 22:51:07 +02:00
Adam Stachowicz
790c071f2c Resize apple icon to 192px 2021-07-17 22:45:28 +02:00
Adam Stachowicz
149688e669 Add robots.txt 2021-07-17 22:24:10 +02:00
Niyas
7dae5279fb Docker healthcheck
Copied from https://scoutapm.com/blog/how-to-use-docker-healthcheck
2021-07-17 20:08:01 +05:30
Niyas
c203317b3b Docker healthcheck
Copied from https://scoutapm.com/blog/how-to-use-docker-healthcheck
2021-07-17 20:07:35 +05:30
Niyas
01f2fccb23 Update notification.js 2021-07-17 18:59:26 +05:30
Niyas
7808aef58f Pushover support 2021-07-17 18:42:54 +05:30
Niyas
ce2d78f45a Pushover support 2021-07-17 17:55:02 +05:30
Niyas
20cad50593 Pushover support 2021-07-17 17:49:56 +05:30
Niyas
829a2a191d Footer center align 2021-07-17 13:42:05 +05:30
Niyas
65b320d06b Slack Enhancements 2021-07-17 12:48:42 +05:30
Niyas
1935da5b16 Slack Enhancements 2021-07-17 12:47:52 +05:30
LouisLam
78f5d2cd8b update to 1.0.5 2021-07-17 02:31:31 +08:00
LouisLam
f62b70c9a9 add nightly to version number 2021-07-17 02:30:16 +08:00
LouisLam
dfa9b3a0ca fix require() actually not working after build in the frontend 2021-07-17 00:51:28 +08:00
LouisLam
b3bff8d735 add graceful shutdown 2021-07-16 01:44:51 +08:00
Louis Lam
f2af5bc064 Merge pull request #46 from NiNiyas/slack-webhook
Added Slack webhook notification
2021-07-15 11:59:41 +08:00
Louis Lam
91b736f391 Merge pull request #52 from philippdormann/feature/gotify-upstream-merge
customize Gotify priority
2021-07-15 11:59:20 +08:00
Louis Lam
275f77d4bb Merge pull request #45 from R0GGER/master
Apple icon for iPhone/iPad
2021-07-15 11:03:46 +08:00
Louis Lam
b00524067a Update README.md 2021-07-15 10:59:36 +08:00
Philipp Dormann
25a93b05dc easier merging 🤞 2021-07-14 22:00:15 +02:00
Philipp Dormann
53e203d2f9 add gotify priority
ref https://github.com/louislam/uptime-kuma/pull/43
closes https://github.com/louislam/uptime-kuma/issues/50
2021-07-14 21:56:38 +02:00
LouisLam
f48f957ba9 update to 1.0.4 2021-07-15 01:44:15 +08:00
LouisLam
bfb117cb76 minor 2021-07-15 01:01:47 +08:00
LouisLam
2b8e33caed dockerfile: change the base image to node:14-alpine3.12; add apprise cli, prepare for implementing notification 2021-07-15 00:36:44 +08:00
Niyas
60493f0f86 Updated Slack test notification 2021-07-14 21:59:16 +05:30
Niyas
63c6e29e62 Added Slack Webhook support 2021-07-14 21:08:38 +05:30
Niyas
5f6d5588a6 Added Slack Webhook support 2021-07-14 21:07:14 +05:30
R0GGER
18744d834f Add files via upload 2021-07-14 14:35:59 +02:00
R0GGER
8dd5b97b79 Apple icon 2021-07-14 14:34:50 +02:00
Louis Lam
386c8bfdf1 Merge pull request #43 from philippdormann/feature/gotify-upstream-merge
 Gotify Support
2021-07-14 17:36:21 +08:00
Philipp Dormann
126f00e739 added Gotify Support 2021-07-14 11:25:10 +02:00
Louis Lam
80466ac957 Update README.md 2021-07-14 17:10:51 +08:00
LouisLam
3b52433202 cache the sqlite built when docker build 2021-07-14 12:42:52 +08:00
Louis Lam
137f5da3da Update README.md 2021-07-14 01:48:55 +08:00
Louis Lam
338d002d42 Update README.md 2021-07-14 01:39:04 +08:00
Louis Lam
77ab9fbc57 Add some shields by shields.io 2021-07-14 01:36:25 +08:00
LouisLam
b6b7835d7e update to 1.0.3 2021-07-13 23:34:33 +08:00
LouisLam
d4fe5908f5 fix merging problem 2021-07-13 23:29:40 +08:00
LouisLam
af838d62e8 update 1.0.2 2021-07-13 23:09:12 +08:00
LouisLam
5a6e83b777 remove debug msg 2021-07-13 23:05:52 +08:00
LouisLam
c81930cacc add build-docker-nightly script 2021-07-13 23:03:55 +08:00
LouisLam
6d4694da43 add version-global-replace.js 2021-07-13 22:58:30 +08:00
LouisLam
9c23cd09ce use bcrypt for password hash 2021-07-13 22:22:46 +08:00
LouisLam
a60bf1528a drop ie support when build the frontend 2021-07-13 18:34:09 +08:00
LouisLam
1f3b337806 reset auto increment for new users 2021-07-13 18:21:06 +08:00
LouisLam
010ebea210 show version in the footer 2021-07-13 18:08:12 +08:00
LouisLam
b3a5d868a7 catch timezone error if browser do not have 2021-07-13 17:46:39 +08:00
LouisLam
312dec7393 add png icon 2021-07-13 12:38:59 +08:00
LouisLam
be1ef24cce add a comment 2021-07-13 12:24:33 +08:00
Louis Lam
c5de82b220 Merge pull request #35 from louislam/revert-32-feature/darkmode
Revert "basic darkmode"
2021-07-13 12:16:24 +08:00
Louis Lam
fef41b44a8 Revert "basic darkmode" 2021-07-13 12:16:11 +08:00
Louis Lam
6af65b688d Merge pull request #32 from philippdormann/feature/darkmode
basic darkmode
2021-07-13 11:58:57 +08:00
LouisLam
3e4a98b6bc Merge branch 'dev'
# Conflicts:
#	server/notification.js
2021-07-13 11:42:51 +08:00
LouisLam
866bf56319 add build-docker-nightly script 2021-07-13 11:32:40 +08:00
LouisLam
99afdabcac change the docker base image to node:14-alpine3.14, reduce the container size 2021-07-13 11:32:09 +08:00
LouisLam
0f1a95fde9 smtp without username password 2021-07-13 11:01:02 +08:00
LouisLam
edbab8163e update .editorconfig 2021-07-13 10:31:31 +08:00
LouisLam
551d00fc24 add some comments and remove traefik-network from docker-composer.yml 2021-07-13 10:28:07 +08:00
Louis Lam
3e4cdbecf2 Merge pull request #28 from yatadev/master
Create docker-compose.yml
2021-07-13 10:21:21 +08:00
Louis Lam
622681470d Merge pull request #22 from TheGuyDanish/master
Discord notification rework
2021-07-13 10:20:47 +08:00
Philipp Dormann
d9e2c230bf Merge branch 'master' of philippdormann/uptime-kuma into philippdormann/uptime-kuma->feature/darkmode
darkmode based on css variables. ref https://github.com/louislam/uptime-kuma/issues/21
2021-07-12 22:21:19 +02:00
Philipp Dormann
010302395f clean, multistage Dockerfile 2021-07-12 22:11:47 +02:00
jacr13
e053ee6573 fix bad pasting 2021-07-12 22:10:26 +02:00
Philipp Dormann
c4bc95927f dependency bumps 2021-07-12 22:09:27 +02:00
jacr13
3e305b79b2 remove debub console log 2021-07-12 22:08:42 +02:00
jacr13
c6237277c0 add support for signal notifications 2021-07-12 22:06:03 +02:00
Philipp Dormann
900219deb1 Merge remote-tracking branch 'theguydanish/master'
# Conflicts:
#	package-lock.json
#	package.json
2021-07-12 21:58:13 +02:00
Philipp Dormann
7ebeee3455 README: add sample docker-compose link
ref https://github.com/louislam/uptime-kuma/issues/25
2021-07-12 21:53:49 +02:00
Philipp Dormann
0abd3b2d16 README cleanup 2021-07-12 21:53:28 +02:00
Philipp Dormann
f452bf6b13 properly name Dockerfile 2021-07-12 21:50:51 +02:00
Philipp Dormann
8cd90d1e96 🐳 Docker 2021-07-12 21:50:39 +02:00
Philipp Dormann
789094a2ee formatting socket.js + deal with broken windows ports - default :50013 2021-07-12 21:49:18 +02:00
Philipp Dormann
5515437eab 🧹 cleanup 2021-07-12 21:47:32 +02:00
Philipp Dormann
7acb347012 🧹 fix formatting in server.js 2021-07-12 21:43:31 +02:00
Philipp Dormann
9d57e93367 Merge branch 'master' of https://github.com/philippdormann/uptime-kuma 2021-07-12 21:41:01 +02:00
Philipp Dormann
dae92d0ae4 Merge remote-tracking branch 'upstream/master'
# Conflicts:
#	package.json
2021-07-12 21:40:35 +02:00
LouisLam
1259ff5368 smtp username/password is not required 2021-07-13 01:02:50 +08:00
yatadev
8debce82b1 Create docker-compose.yml 2021-07-12 18:23:38 +02:00
LouisLam
11a2adcb7c Merge remote-tracking branch 'origin/master' 2021-07-12 23:29:13 +08:00
LouisLam
ad615d1a90 remove some timezones which may cause error 2021-07-12 23:28:56 +08:00
TheGuyDanish
613c42b6d8 Discord revamp! Changed from bot to webhook, removed discord.js dep 2021-07-12 14:13:36 +01:00
Louis Lam
a6e16116f2 improve the docker script 2021-07-12 20:08:51 +08:00
Louis Lam
c7dfb36349 Update README.md 2021-07-12 20:00:12 +08:00
LouisLam
459dde2761 update the setup script to 1.0.1 2021-07-12 19:03:25 +08:00
LouisLam
cb94ab3bb5 add update guide 2021-07-12 18:59:48 +08:00
LouisLam
0176857a2c add ability to change the listening port and hostname 2021-07-12 18:33:25 +08:00
Philipp Dormann
763d7f2683 Merge branch 'louislam:master' into master 2021-07-12 12:01:00 +02:00
Louis Lam
c436ef4e05 Update README.md 2021-07-12 11:42:36 +08:00
LouisLam
56fcfc9369 fix show N/A if the ping is 0ms 2021-07-12 11:20:18 +08:00
LouisLam
a9d19ae06a support json for keyword type 2021-07-12 10:52:41 +08:00
Louis Lam
35ce54f30c Merge pull request #6 from TheGuyDanish/patch-1
Introduce custom user agent. Fixes #5
2021-07-12 09:39:15 +08:00
Philipp Dormann
e4f38d833d 🌑 darkmode support for nav link hover 2021-07-12 00:41:28 +02:00
Philipp Dormann
8b83266b00 🌑 add darkmode support for focused input elements 2021-07-12 00:37:08 +02:00
Philipp Dormann
6fb1b344f6 🌑 darkmode support on form elements 2021-07-12 00:33:52 +02:00
Philipp Dormann
b15b44e290 🐳 move Dockerfile to base node:alpine image
reduces size from about 1.08GB to 345MB (still not great but hey)
2021-07-12 00:28:11 +02:00
Philipp Dormann
66d991bd05 🐞 added missing v-bind:key to Dashboard 2021-07-12 00:27:29 +02:00
Philipp Dormann
673d3c124c 🚧 WIP on darkmode 🌑 2021-07-12 00:26:33 +02:00
Philipp Dormann
e568cad22c dependency bump + version pin 2021-07-12 00:25:22 +02:00
TheGuyDanish
f84f7aca75 Introduce custom user agent. Fixes #5
Quick and easy fix. Could be improved by adding a version number as well. Like `Uptime-Kuma/0.0.1`, for example.
2021-07-11 21:01:34 +01:00
LouisLam
b198b3dde4 Merge remote-tracking branch 'origin/master' 2021-07-12 01:18:18 +08:00
LouisLam
0b294815c7 add back arm/v7 for build-docker 2021-07-12 01:18:02 +08:00
Louis Lam
83935a2cf4 Update README.md 2021-07-11 23:41:21 +08:00
Louis Lam
838913f0a1 Update README.md 2021-07-11 23:41:04 +08:00
30 changed files with 1210 additions and 277 deletions

View File

@@ -2,3 +2,12 @@
/dist
/node_modules
/data/kuma.db
/.do
**/.dockerignore
**/.git
**/.gitignore
**/docker-compose*
**/Dockerfile*
LICENSE
README.md
.editorconfig

View File

@@ -13,3 +13,6 @@ trim_trailing_whitespace = false
[*.yaml]
indent_size = 2
[*.yml]
indent_size = 2

View File

@@ -1,5 +1,8 @@
# Uptime Kuma
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a>
<div align="center" width="100%">
<img src="./public/icon.svg" width="128" alt="" />
</div>
@@ -18,12 +21,23 @@ It is a self-hosted monitoring tool like "Uptime Robot".
# How to Use
### Docker
```bash
docker run -d --restart=always -p 3001:3001 louislam/uptime-kuma
# Create a volume
docker volume create uptime-kuma
# Start the container
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
```
Browse to http://localhost:3001 after started.
Change Port and Volume
```bash
docker run -d --restart=always -p <YOUR_PORT>:3001 -v <YOUR_DIR OR VOLUME>:/app/data --name uptime-kuma louislam/uptime-kuma:1
```
### Without Docker
Required Tools: Node.js >= 14, git and pm2.
@@ -36,11 +50,14 @@ npm run setup
# Option 1. Try it
npm run start-server
# (Recommanded)
# (Recommended)
# Option 2. Run in background using PM2
# Install PM2 if you don't have: npm install pm2 -g
pm2 start npm --name uptime-kuma -- run start-server
# Listen to different port or hostname
pm2 start npm --name uptime-kuma -- run start-server -- --port=80 --hostname=0.0.0.0
```
Browse to http://localhost:3001 after started.
@@ -49,6 +66,25 @@ Browse to http://localhost:3001 after started.
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/louislam/uptime-kuma/tree/master&refcode=e2c7eb658434)
Choose Cheapest Plan is enough. (US$ 5)
# How to Update
### Docker
Re-pull the latest docker image and create another container with the same volume.
PS: For every new release, it takes some time to build the docker image, please be patient if it is not available yet.
### Without Docker
```bash
git fetch --all
git checkout 1.0.6 --force
npm install
npm run build
pm2 restart uptime-kuma
```
# More Screenshots
@@ -73,3 +109,11 @@ Telegram Notification Sample:
If you love this project, please consider giving me a ⭐.
# Contribute
If you want to report a bug or request a new feature. Free feel to open a new issue.
If you want to modify Uptime Kuma, this guideline maybe useful for you: https://github.com/louislam/uptime-kuma/wiki/%5BDev%5D-Setup-Development-Environment
English proofreading is needed too, because my grammar is not that great sadly. Feel free to correct my grammar in this Readme, source code or wiki.

Binary file not shown.

13
docker-compose.yml Normal file
View File

@@ -0,0 +1,13 @@
# Simple docker-composer.yml
# You can change your port or volume location
version: '3.3'
services:
uptime-kuma:
image: louislam/uptime-kuma
container_name: uptime-kuma
volumes:
- ./uptime-kuma:/app/data
ports:
- 3001:3001

View File

@@ -1,10 +1,41 @@
FROM node:14
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
FROM node:14-alpine3.12 AS release
WORKDIR /app
# split the sqlite install here, so that it can caches the arm prebuilt
RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev && \
ln -s /usr/bin/python3 /usr/bin/python && \
npm install sqlite3@5.0.2 bcrypt@5.0.1 && \
apk del .build-deps
# Touching above code may causes sqlite3 re-compile again, painful slow.
# Install apprise
# Hate pip!!! I never run pip install successfully in first run for anything in my life without Google :/
# Compilation Fail 1 => Google Search "alpine ffi.h" => Add libffi-dev
# Compilation Fail 2 => Google Search "alpine cargo" => Add cargo
# Compilation Fail 3 => Google Search "alpine opensslv.h" => Add openssl-dev
# Compilation Fail 4 => Google Search "alpine opensslv.h" again => Change to libressl-dev musl-dev
# Compilation Fail 5 => Google Search "ERROR: libressl3.3-libtls-3.3.3-r0: trying to overwrite usr/lib/libtls.so.20 owned by libretls-3.3.3-r0." again => Change back to openssl-dev with musl-dev
# Runtime Error => ModuleNotFoundError: No module named 'six' => pip3 install six
# Runtime Error 2 => ModuleNotFoundError: No module named 'six' => apk add py3-six
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
RUN apk add --no-cache python3 py3-pip py3-six cargo
RUN apk add --no-cache --virtual .build-deps libffi-dev musl-dev openssl-dev python3-dev && \
pip3 install apprise && \
apk del .build-deps
RUN apprise --version
# New things add here
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3001
VOLUME ["/app/data"]
HEALTHCHECK --interval=60s --timeout=30s --start-period=300s CMD node extra/healthcheck.js
CMD ["npm", "run", "start-server"]
FROM release AS nightly
RUN npm run mark-as-nightly

19
extra/healthcheck.js Normal file
View File

@@ -0,0 +1,19 @@
var http = require("http");
var options = {
host: "localhost",
port: "3001",
timeout: 2000,
};
var request = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
if (res.statusCode == 200) {
process.exit(0);
} else {
process.exit(1);
}
});
request.on("error", function (err) {
console.log("ERROR");
process.exit(1);
});
request.end();

40
extra/mark-as-nightly.js Normal file
View File

@@ -0,0 +1,40 @@
/**
* String.prototype.replaceAll() polyfill
* https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/
* @author Chris Ferdinandi
* @license MIT
*/
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function(str, newStr){
// If a regex pattern
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
return this.replace(str, newStr);
}
// If a string
return this.replace(new RegExp(str, 'g'), newStr);
};
}
const pkg = require('../package.json');
const fs = require("fs");
const oldVersion = pkg.version
const newVersion = oldVersion + "-nightly"
console.log("Old Version: " + oldVersion)
console.log("New Version: " + newVersion)
if (newVersion) {
// Process package.json
pkg.version = newVersion
pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion)
pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion)
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n")
// Process README.md
if (fs.existsSync("README.md")) {
fs.writeFileSync("README.md", fs.readFileSync("README.md", 'utf8').replaceAll(oldVersion, newVersion))
}
}

View File

@@ -0,0 +1,39 @@
/**
* String.prototype.replaceAll() polyfill
* https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/
* @author Chris Ferdinandi
* @license MIT
*/
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function(str, newStr){
// If a regex pattern
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
return this.replace(str, newStr);
}
// If a string
return this.replace(new RegExp(str, 'g'), newStr);
};
}
const pkg = require('../package.json');
const fs = require("fs");
const oldVersion = pkg.version
const newVersion = process.argv[2]
console.log("Old Version: " + oldVersion)
console.log("New Version: " + newVersion)
if (newVersion) {
// Process package.json
pkg.version = newVersion
pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion)
pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion)
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n")
// Process README.md
fs.writeFileSync("README.md", fs.readFileSync("README.md", 'utf8').replaceAll(oldVersion, newVersion))
}

View File

@@ -3,7 +3,10 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#5cdd8b" />
<meta name="description" content="Uptime Kuma monitoring tool" />
<title>Uptime Kuma</title>
</head>
<body>

444
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "uptime-kuma",
"version": "1.0.0",
"version": "1.0.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -29,21 +29,6 @@
"to-fast-properties": "^2.0.0"
}
},
"@discordjs/collection": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
},
"@discordjs/form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"@popperjs/core": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
@@ -55,37 +40,43 @@
"integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg=="
},
"@types/cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg=="
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
},
"@types/cors": {
"version": "2.8.10",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz",
"integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ=="
"version": "2.8.12",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
},
"@types/estree": {
"version": "0.0.48",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
"integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==",
"dev": true
},
"@types/node": {
"version": "15.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz",
"integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA=="
"version": "16.3.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.3.tgz",
"integrity": "sha512-8h7k1YgQKxKXWckzFCMfsIwn0Y61UK6tlD6y2lOb3hTOIMlK3t9/QwHOhc81TwU+RMf0As5fj7NPjroERCnejQ=="
},
"@vitejs/plugin-legacy": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.4.3.tgz",
"integrity": "sha512-lxZUJaMWYMQuqvZM1wPzDP6KABQgA/drVL5fnaygEPcz9adc2OHhfFNN/SvvHQ1V0rP8gybIc7uA+iI1gAdkVQ==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.4.4.tgz",
"integrity": "sha512-pVYeQUDPG5InWwrTu7acy187WWjGonJnL/GMqMLmeKCFiwkZ6UcsoUjojiKmCUI0nAJTrrKH5lhjTqkccY9Iow==",
"dev": true,
"requires": {
"@babel/standalone": "^7.14.7",
"core-js": "^3.15.1",
"core-js": "^3.15.2",
"magic-string": "^0.25.7",
"regenerator-runtime": "^0.13.7",
"systemjs": "^6.10.1"
"systemjs": "^6.10.2"
}
},
"@vitejs/plugin-vue": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.3.tgz",
"integrity": "sha512-LlnLpObkGKZ+b7dcpL4T24l13nPSHLjo+6Oc7MbZiKz5PMAUzADfNJ3EKfYIQ0l0969nxf2jp/9vsfnuJ7h6fw==",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.5.tgz",
"integrity": "sha512-GIR31mdXTEfvElmBUaRhDc5v7lfdkEdawWQqJRiaRL/5qKsH+xusukglkvJz5y7+c6dEpxgmvcATv2BbB7+fzQ==",
"dev": true
},
"@vue/compiler-core": {
@@ -110,17 +101,18 @@
}
},
"@vue/compiler-sfc": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.1.tgz",
"integrity": "sha512-lSgMsZaYHF+bAgryq5aUqpvyfhu52GJI2/4LoiJCE5uaxc6FCZfxfgqgw/d9ltiZghv+HiISFtmQVAVvlsk+/w==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.5.tgz",
"integrity": "sha512-mtMY6xMvZeSRx9MTa1+NgJWndrkzVTdJ1pQAmAKQuxyb5LsHVvrgP7kcQFvxPHVpLVTORbTJWHaiqoKrJvi1iA==",
"dev": true,
"requires": {
"@babel/parser": "^7.13.9",
"@babel/types": "^7.13.0",
"@vue/compiler-core": "3.1.1",
"@vue/compiler-dom": "3.1.1",
"@vue/compiler-ssr": "3.1.1",
"@vue/shared": "3.1.1",
"@types/estree": "^0.0.48",
"@vue/compiler-core": "3.1.5",
"@vue/compiler-dom": "3.1.5",
"@vue/compiler-ssr": "3.1.5",
"@vue/shared": "3.1.5",
"consolidate": "^0.16.0",
"estree-walker": "^2.0.1",
"hash-sum": "^2.0.0",
@@ -131,16 +123,78 @@
"postcss-modules": "^4.0.0",
"postcss-selector-parser": "^6.0.4",
"source-map": "^0.6.1"
},
"dependencies": {
"@vue/compiler-core": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz",
"integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==",
"dev": true,
"requires": {
"@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0",
"@vue/shared": "3.1.5",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz",
"integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==",
"dev": true,
"requires": {
"@vue/compiler-core": "3.1.5",
"@vue/shared": "3.1.5"
}
},
"@vue/shared": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
"dev": true
}
}
},
"@vue/compiler-ssr": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.1.tgz",
"integrity": "sha512-7H6krZtVt3h/YzfNp7eYK41hMDz8ZskiBy+Wby+EDRINX6BD9JQ5C8zyy2xAa7T6Iz2VrQzsaJ/Bb52lTPSS5A==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.5.tgz",
"integrity": "sha512-CU5N7Di/a4lyJ18LGJxJYZS2a8PlLdWpWHX9p/XcsjT2TngMpj3QvHVRkuik2u8QrIDZ8OpYmTyj1WDNsOV+Dg==",
"dev": true,
"requires": {
"@vue/compiler-dom": "3.1.1",
"@vue/shared": "3.1.1"
"@vue/compiler-dom": "3.1.5",
"@vue/shared": "3.1.5"
},
"dependencies": {
"@vue/compiler-core": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz",
"integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==",
"dev": true,
"requires": {
"@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0",
"@vue/shared": "3.1.5",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz",
"integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==",
"dev": true,
"requires": {
"@vue/compiler-core": "3.1.5",
"@vue/shared": "3.1.5"
}
},
"@vue/shared": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
"dev": true
}
}
},
"@vue/devtools-api": {
@@ -185,14 +239,6 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -202,6 +248,14 @@
"negotiator": "0.6.2"
}
},
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"requires": {
"debug": "4"
}
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -243,6 +297,11 @@
"readable-stream": "^2.0.6"
}
},
"args-parser": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/args-parser/-/args-parser-1.3.0.tgz",
"integrity": "sha512-If3Zi4BSjlQIJ9fgAhSiKi0oJtgMzSqh0H4wvl7XSeO16FKx7QqaHld8lZeEajPX7y1C5qKKeNgyrfyvmjmjUQ=="
},
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@@ -403,6 +462,70 @@
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"bcrypt": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
"integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==",
"requires": {
"@mapbox/node-pre-gyp": "^1.0.0",
"node-addon-api": "^3.1.0"
},
"dependencies": {
"@mapbox/node-pre-gyp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
"integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==",
"requires": {
"detect-libc": "^1.0.3",
"https-proxy-agent": "^5.0.0",
"make-dir": "^3.1.0",
"node-fetch": "^2.6.1",
"nopt": "^5.0.0",
"npmlog": "^4.1.2",
"rimraf": "^3.0.2",
"semver": "^7.3.4",
"tar": "^6.1.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"requires": {
"abbrev": "1"
}
},
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"requires": {
"glob": "^7.1.3"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@@ -477,9 +600,9 @@
}
},
"bootstrap": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.1.tgz",
"integrity": "sha512-Fl79+wsLOZKoiU345KeEaWD0ik8WKRI5zm0YSPj2oF1Qr+BO7z0fco6GbUtqjoG1h4VI89PeKJnMsMMVQdKKTw=="
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.2.tgz",
"integrity": "sha512-1Ge963tyEQWJJ+8qtXFU6wgmAVj9gweEjibUdbmcCEYsn38tVwRk8107rk2vzt6cfQcRr3SlZ8aQBqaD8aqf+Q=="
},
"brace-expansion": {
"version": "1.1.11",
@@ -601,6 +724,11 @@
"delayed-stream": "~1.0.0"
}
},
"command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
},
"commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
@@ -699,9 +827,9 @@
}
},
"dayjs": {
"version": "1.10.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz",
"integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g=="
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz",
"integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw=="
},
"debug": {
"version": "4.3.1",
@@ -788,28 +916,6 @@
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"discord.js": {
"version": "12.5.3",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz",
"integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==",
"requires": {
"@discordjs/collection": "^0.1.6",
"@discordjs/form-data": "^3.0.1",
"abort-controller": "^3.0.0",
"node-fetch": "^2.6.1",
"prism-media": "^1.2.9",
"setimmediate": "^1.0.5",
"tweetnacl": "^1.0.3",
"ws": "^7.4.4"
},
"dependencies": {
"tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
}
}
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -866,9 +972,9 @@
}
},
"engine.io-client": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.1.tgz",
"integrity": "sha512-jPFpw2HLL0lhZ2KY0BpZhIJdleQcUO9W1xkIpo0h3d6s+5D6+EV/xgQw9qWOmymszv2WXef/6KUUehyxEKomlQ==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz",
"integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==",
"requires": {
"base64-arraybuffer": "0.1.4",
"component-emitter": "~1.3.0",
@@ -890,9 +996,9 @@
}
},
"esbuild": {
"version": "0.12.9",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.9.tgz",
"integrity": "sha512-MWRhAbMOJ9RJygCrt778rz/qNYgA4ZVj6aXnNPxFjs7PmIpb0fuB9Gmg5uWrr6n++XKwwm/RmSz6RR5JL2Ocsw==",
"version": "0.12.15",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.15.tgz",
"integrity": "sha512-72V4JNd2+48eOVCXx49xoSWHgC3/cCy96e7mbXKY+WOWghN00cCmlGnwVLRhRHorvv0dgCyuMYBZlM2xDM5OQw==",
"dev": true
},
"escape-html": {
@@ -915,11 +1021,6 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@@ -1244,6 +1345,14 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"requires": {
"minipass": "^3.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -1484,6 +1593,14 @@
"toidentifier": "1.0.0"
}
},
"http-graceful-shutdown": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/http-graceful-shutdown/-/http-graceful-shutdown-3.1.2.tgz",
"integrity": "sha512-2vmU3kWOsZqZy4Kn4EZp00CF+6glpNNN/NAYJPkO9bnMX/D8sRl29TsxIu9Vgyo8ygtCWazWJp720zHfqhSdXg==",
"requires": {
"debug": "^4.3.1"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@@ -1495,6 +1612,15 @@
"sshpk": "^1.7.0"
}
},
"https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"requires": {
"agent-base": "6",
"debug": "4"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -1926,6 +2052,21 @@
"sourcemap-codec": "^1.4.4"
}
},
"make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"requires": {
"semver": "^6.0.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
"make-iterator": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
@@ -2099,6 +2240,37 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"minipass": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
"integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
"requires": {
"yallist": "^4.0.0"
},
"dependencies": {
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"minizlib": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"requires": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"dependencies": {
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
@@ -2118,6 +2290,11 @@
}
}
},
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2317,9 +2494,9 @@
}
},
"nodemailer": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.2.tgz",
"integrity": "sha512-YSzu7TLbI+bsjCis/TZlAXBoM4y93HhlIgo0P5oiA2ua9Z4k+E2Fod//ybIzdJxOlXGRcHIh/WaeCBehvxZb/Q=="
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.3.tgz",
"integrity": "sha512-faZFufgTMrphYoDjvyVpbpJcYzwyFnbAMmQtj1lVBYAUSm3SOy2fIdd9+Mr4UxPosBa0JRw9bJoIwQn+nswiew=="
},
"nopt": {
"version": "3.0.6",
@@ -2653,11 +2830,6 @@
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"prism-media": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz",
"integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw=="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -2877,9 +3049,9 @@
}
},
"rollup": {
"version": "2.52.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz",
"integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==",
"version": "2.53.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.53.2.tgz",
"integrity": "sha512-1CtEYuS5CRCzFZ7SNW5528SlDlk4VDXIRGwbm/2POQxA/G4+7/crIqJwkmnj8Q/74hGx4oVlNvh4E1CJQ5hZ6w==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"
@@ -2904,9 +3076,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sass": {
"version": "1.35.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.35.1.tgz",
"integrity": "sha512-oCisuQJstxMcacOPmxLNiLlj4cUyN2+8xJnG7VanRoh2GOLr9RqkvI4AxA4a6LHVg/rsu+PmxXeGhrdSF9jCiQ==",
"version": "1.35.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.35.2.tgz",
"integrity": "sha512-jhO5KAR+AMxCEwIH3v+4zbB2WB0z67V1X0jbapfVwQQdjHZUGUyukpnoM6+iCMfsIUC016w9OPKQ5jrNOS9uXw==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0"
@@ -3001,11 +3173,6 @@
}
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
@@ -3132,19 +3299,19 @@
}
},
"socket.io": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.1.2.tgz",
"integrity": "sha512-xK0SD1C7hFrh9+bYoYCdVt+ncixkSLKtNLCax5aEy1o3r5PaO5yQhVb97exIe67cE7lAK+EpyMytXWTWmyZY8w==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.1.3.tgz",
"integrity": "sha512-tLkaY13RcO4nIRh1K2hT5iuotfTaIQw7cVIe0FUykN3SuQi0cm7ALxuyT5/CtDswOMWUzMGTibxYNx/gU7In+Q==",
"requires": {
"@types/cookie": "^0.4.0",
"@types/cors": "^2.8.8",
"@types/cors": "^2.8.10",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"debug": "~4.3.1",
"engine.io": "~5.1.0",
"socket.io-adapter": "~2.3.0",
"socket.io-parser": "~4.0.3"
"engine.io": "~5.1.1",
"socket.io-adapter": "~2.3.1",
"socket.io-parser": "~4.0.4"
}
},
"socket.io-adapter": {
@@ -3153,15 +3320,15 @@
"integrity": "sha512-8cVkRxI8Nt2wadkY6u60Y4rpW3ejA1rxgcK2JuyIhmF+RMNpTy1QRtkHIDUOf3B4HlQwakMsWbKftMv/71VMmw=="
},
"socket.io-client": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.2.tgz",
"integrity": "sha512-RDpWJP4DQT1XeexmeDyDkm0vrFc0+bUsHDKiVGaNISJvJonhQQOMqV9Vwfg0ZpPJ27LCdan7iqTI92FRSOkFWQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz",
"integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==",
"requires": {
"@types/component-emitter": "^1.2.10",
"backo2": "~1.0.2",
"component-emitter": "~1.3.0",
"debug": "~4.3.1",
"engine.io-client": "~5.1.1",
"engine.io-client": "~5.1.2",
"parseuri": "0.0.6",
"socket.io-parser": "~4.0.4"
}
@@ -3317,6 +3484,31 @@
"integrity": "sha512-PwaC0Z6Y1E6gFekY2u38EC5+5w2M65jYVrD1aAcOptpHVhCwPIwPFJvYJyryQKUyeuQ5bKKI3PBHWNjdE9aizg==",
"dev": true
},
"tar": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
"requires": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^3.0.0",
"minizlib": "^2.1.1",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"dependencies": {
"chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"tarn": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz",
@@ -3531,14 +3723,14 @@
}
},
"vite": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.3.8.tgz",
"integrity": "sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-2.4.2.tgz",
"integrity": "sha512-2MifxD2I9fjyDmmEzbULOo3kOUoqX90A58cT6mECxoVQlMYFuijZsPQBuA14mqSwvV3ydUsqnq+BRWXyO9Qa+w==",
"dev": true,
"requires": {
"esbuild": "^0.12.8",
"fsevents": "~2.3.2",
"postcss": "^8.3.4",
"postcss": "^8.3.5",
"resolve": "^1.20.0",
"rollup": "^2.38.5"
}

View File

@@ -1,29 +1,42 @@
{
"name": "uptime-kuma",
"version": "1.0.0",
"version": "1.0.6",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/louislam/uptime-kuma.git"
},
"scripts": {
"dev": "vite --host",
"start-server": "node server/server.js",
"update": "",
"build": "vite build",
"vite-preview-dist": "vite preview --host",
"build-docker": "docker buildx build --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 . --push",
"setup": "git checkout 1.0.0 && npm install && npm run build"
"build-docker": "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.0.6 --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",
"build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push",
"setup": "git checkout 1.0.6 && npm install && npm run build",
"version-global-replace": "node extra/version-global-replace.js",
"mark-as-nightly": "node extra/mark-as-nightly.js"
},
"dependencies": {
"@popperjs/core": "^2.9.2",
"args-parser": "^1.3.0",
"axios": "^0.21.1",
"bootstrap": "^5.0.0",
"dayjs": "^1.10.4",
"discord.js": "^12.5.3",
"bcrypt": "^5.0.1",
"bootstrap": "^5.0.2",
"command-exists": "^1.2.9",
"dayjs": "^1.10.6",
"express": "^4.17.1",
"form-data": "^4.0.0",
"http-graceful-shutdown": "^3.1.2",
"jsonwebtoken": "^8.5.1",
"nodemailer": "^6.6.2",
"nodemailer": "^6.6.3",
"password-hash": "^1.2.2",
"redbean-node": "0.0.20",
"socket.io": "^4.0.2",
"socket.io-client": "^4.1.2",
"socket.io": "^4.1.3",
"socket.io-client": "^4.1.3",
"sqlite3": "^5.0.2",
"tcp-ping": "^0.1.1",
"vue": "^3.0.5",
"vue-confirm-dialog": "^1.0.2",
@@ -31,11 +44,11 @@
"vue-toastification": "^2.0.0-rc.1"
},
"devDependencies": {
"@vitejs/plugin-legacy": "^1.4.3",
"@vitejs/plugin-vue": "^1.2.3",
"@vue/compiler-sfc": "^3.0.5",
"@vitejs/plugin-legacy": "^1.4.4",
"@vitejs/plugin-vue": "^1.2.5",
"@vue/compiler-sfc": "^3.1.5",
"core-js": "^3.15.2",
"sass": "^1.35.1",
"vite": "^2.3.7"
"sass": "^1.35.2",
"vite": "^2.4.2"
}
}

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

3
public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -71,7 +71,9 @@ class Monitor extends BeanModel {
try {
if (this.type === "http" || this.type === "keyword") {
let startTime = dayjs().valueOf();
let res = await axios.get(this.url)
let res = await axios.get(this.url, {
headers: { 'User-Agent':'Uptime-Kuma' }
})
bean.msg = `${res.status} - ${res.statusText}`
bean.ping = dayjs().valueOf() - startTime;
@@ -79,7 +81,14 @@ class Monitor extends BeanModel {
bean.status = 1;
} else {
if (res.data.includes(this.keyword)) {
let data = res.data;
// Convert to string for object/array
if (typeof data !== "string") {
data = JSON.stringify(data)
}
if (data.includes(this.keyword)) {
bean.msg += ", keyword is found"
bean.status = 1;
} else {

View File

@@ -2,10 +2,22 @@ const axios = require("axios");
const {R} = require("redbean-node");
const FormData = require('form-data');
const nodemailer = require("nodemailer");
const Discord = require('discord.js');
const child_process = require("child_process");
class Notification {
/**
*
* @param notification
* @param msg
* @param monitorJSON
* @param heartbeatJSON
* @returns {Promise<string>} Successful msg
* Throw Error with fail msg
*/
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully. ";
if (notification.type === "telegram") {
try {
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
@@ -14,15 +26,32 @@ class Notification {
text: msg,
}
})
return true;
return okMsg;
} catch (error) {
console.log(error)
return false;
let msg = (error.response.data.description) ? error.response.data.description : "Error without description"
throw new Error(msg)
}
} else if (notification.type === "gotify") {
try {
if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) {
notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1);
}
await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, {
"message": msg,
"priority": notification.gotifyPriority || 8,
"title": "Uptime-Kuma"
})
return okMsg;
} catch (error) {
throwGeneralAxiosError(error)
}
} else if (notification.type === "webhook") {
try {
let data = {
heartbeat: heartbeatJSON,
monitor: monitorJSON,
@@ -44,17 +73,156 @@ class Notification {
}
let res = await axios.post(notification.webhookURL, finalData, config)
return true;
return okMsg;
} catch (error) {
console.log(error)
return false;
throwGeneralAxiosError(error)
}
} else if (notification.type === "smtp") {
return await Notification.smtp(notification, msg)
} else if (notification.type === "discord") {
return await Notification.discord(notification, msg)
try {
// If heartbeatJSON is null, assume we're testing.
if(heartbeatJSON == null) {
let data = {
username: 'Uptime-Kuma',
content: msg
}
let res = await axios.post(notification.discordWebhookUrl, data)
return okMsg;
}
// If heartbeatJSON is not null, we go into the normal alerting loop.
if(heartbeatJSON['status'] == 0) {
var alertColor = "16711680";
} else if(heartbeatJSON['status'] == 1) {
var alertColor = "65280";
}
let data = {
username: 'Uptime-Kuma',
embeds: [{
title: "Uptime-Kuma Alert",
color: alertColor,
fields: [
{
name: "Time (UTC)",
value: heartbeatJSON["time"]
},
{
name: "Message",
value: msg
}
]
}]
}
let res = await axios.post(notification.discordWebhookUrl, data)
return okMsg;
} catch(error) {
throwGeneralAxiosError(error)
}
} else if (notification.type === "signal") {
try {
let data = {
"message": msg,
"number": notification.signalNumber,
"recipients": notification.signalRecipients.replace(/\s/g, '').split(",")
};
let config = {};
let res = await axios.post(notification.signalURL, data, config)
return okMsg;
} catch (error) {
throwGeneralAxiosError(error)
}
} else if (notification.type === "slack") {
try {
if (heartbeatJSON == null) {
let data = {'text': "Uptime Kuma Slack testing successful.", 'channel': notification.slackchannel, 'username': notification.slackusername, 'icon_emoji': notification.slackiconemo}
let res = await axios.post(notification.slackwebhookURL, data)
return okMsg;
}
const time = heartbeatJSON["time"];
let data = {
"text": "Uptime Kuma Alert",
"channel":notification.slackchannel,
"username": notification.slackusername,
"icon_emoji": notification.slackiconemo,
"blocks": [{
"type": "header",
"text": {
"type": "plain_text",
"text": "Uptime Kuma Alert"
}
},
{
"type": "section",
"fields": [{
"type": "mrkdwn",
"text": '*Message*\n'+msg
},
{
"type": "mrkdwn",
"text": "*Time (UTC)*\n"+time
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Visit Uptime Kuma",
},
"value": "Uptime-Kuma",
"url": notification.slackbutton || "https://github.com/louislam/uptime-kuma"
}
]
}
]
}
let res = await axios.post(notification.slackwebhookURL, data)
return okMsg;
} catch (error) {
throwGeneralAxiosError(error)
}
} else if (notification.type === "pushover") {
var pushoverlink = 'https://api.pushover.net/1/messages.json'
try {
if (heartbeatJSON == null) {
let data = {'message': "<b>Uptime Kuma Pushover testing successful.</b>",
'user': notification.pushoveruserkey, 'token': notification.pushoverapptoken, 'sound':notification.pushoversounds,
'priority': notification.pushoverpriority, 'title':notification.pushovertitle, 'retry': "30", 'expire':"3600", 'html': 1}
let res = await axios.post(pushoverlink, data)
return okMsg;
}
let data = {
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" +msg + '\n<b>Time (UTC)</b>:' +time,
"user":notification.pushoveruserkey,
"token": notification.pushoverapptoken,
"sound": notification.pushoversounds,
"priority": notification.pushoverpriority,
"title": notification.pushovertitle,
"retry": "30",
"expire": "3600",
"html": 1
}
let res = await axios.post(pushoverlink, data)
return okMsg;
} catch (error) {
throwGeneralAxiosError(error)
}
} else if (notification.type === "apprise") {
return Notification.apprise(notification, msg)
} else {
throw new Error("Notification type is not supported")
@@ -117,20 +285,47 @@ class Notification {
text: msg,
});
return true;
return "Sent Successfully.";
}
static async discord(notification, msg) {
const client = new Discord.Client();
await client.login(notification.discordToken)
static async apprise(notification, msg) {
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
const channel = await client.channels.fetch(notification.discordChannelID);
await channel.send(msg);
client.destroy()
let output = (s.stdout) ? s.stdout.toString() : 'ERROR: maybe apprise not found';
return true;
if (output) {
if (! output.includes("ERROR")) {
return "Sent Successfully";
} else {
throw new Error(output)
}
} else {
return ""
}
}
static checkApprise() {
let commandExistsSync = require('command-exists').sync;
let exists = commandExistsSync('apprise');
return exists;
}
}
function throwGeneralAxiosError(error) {
let msg = "Error: " + error + " ";
if (error.response && error.response.data) {
if (typeof error.response.data === "string") {
msg += error.response.data;
} else {
msg += JSON.stringify(error.response.data)
}
}
throw new Error(msg)
}
module.exports = {

23
server/password-hash.js Normal file
View File

@@ -0,0 +1,23 @@
const passwordHashOld = require('password-hash');
const bcrypt = require('bcrypt');
const saltRounds = 10;
exports.generate = function (password) {
return bcrypt.hashSync(password, saltRounds);
}
exports.verify = function (password, hash) {
if (isSHA1(hash)) {
return passwordHashOld.verify(password, hash)
} else {
return bcrypt.compareSync(password, hash);
}
}
function isSHA1(hash) {
return (typeof hash === "string" && hash.startsWith("sha1"))
}
exports.needRehash = function (hash) {
return isSHA1(hash);
}

View File

@@ -1,18 +1,30 @@
console.log("Welcome to Uptime Kuma ")
console.log("Importing libraries")
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const dayjs = require("dayjs");
const {R} = require("redbean-node");
const passwordHash = require('password-hash');
const passwordHash = require('./password-hash');
const jwt = require('jsonwebtoken');
const Monitor = require("./model/monitor");
const fs = require("fs");
const {getSettings} = require("./util-server");
const {Notification} = require("./notification")
const gracefulShutdown = require('http-graceful-shutdown');
const {sleep} = require("./util");
const args = require('args-parser')(process.argv);
const version = require('../package.json').version;
const hostname = args.host || "0.0.0.0"
const port = args.port || 3001
console.info("Version: " + version)
console.log("Creating express and socket.io instance")
const app = express();
const server = http.createServer(app);
const io = new Server(server);
app.use(express.json())
let totalClient = 0;
@@ -23,21 +35,21 @@ let needSetup = false;
(async () => {
await initDatabase();
console.log("Adding route")
app.use('/', express.static("dist"));
app.post('/test-webhook', function(request, response, next) {
console.log("Test Webhook (application/json only)")
console.log("Content-Type: " + request.header("Content-Type"))
console.log(request.body)
response.end();
});
app.get('*', function(request, response, next) {
response.sendFile(process.cwd() + '/dist/index.html');
});
console.log("Adding socket handler")
io.on('connection', async (socket) => {
console.log('a user connected');
socket.emit("info", {
version,
})
totalClient++;
if (needSetup) {
@@ -46,7 +58,6 @@ let needSetup = false;
}
socket.on('disconnect', () => {
console.log('user disconnected');
totalClient--;
});
@@ -93,6 +104,14 @@ let needSetup = false;
if (user && passwordHash.verify(data.password, user.password)) {
// Upgrade the hash to bcrypt
if (passwordHash.needRehash(user.password)) {
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
passwordHash.generate(data.password),
user.id
]);
}
await afterLogin(socket, user)
callback({
@@ -218,7 +237,7 @@ let needSetup = false;
});
} catch (e) {
console.log(e)
console.error(e)
callback({
ok: false,
msg: e.message
@@ -419,25 +438,36 @@ let needSetup = false;
try {
checkLogin(socket)
await Notification.send(notification, notification.name + " Testing")
let msg = await Notification.send(notification, notification.name + " Testing")
callback({
ok: true,
msg: "Sent Successfully"
msg
});
} catch (e) {
console.error(e)
callback({
ok: false,
msg: e.message
});
}
});
socket.on("checkApprise", async (callback) => {
try {
checkLogin(socket)
callback(Notification.checkApprise());
} catch (e) {
callback(false);
}
});
});
server.listen(3001, () => {
console.log('Listening on 3001');
console.log("Init")
server.listen(port, hostname, () => {
console.log(`Listening on ${hostname}:${port}`);
startMonitors();
});
@@ -528,15 +558,16 @@ async function initDatabase() {
const path = './data/kuma.db';
if (! fs.existsSync(path)) {
console.log("Copy Database")
console.log("Copying Database")
fs.copyFileSync("./db/kuma.db", path);
}
console.log("Connect to Database")
console.log("Connecting to Database")
R.setup('sqlite', {
filename: path
});
console.log("Connected")
R.freeze(true)
await R.autoloadModels("./server/model");
@@ -551,6 +582,7 @@ async function initDatabase() {
jwtSecretBean.value = passwordHash.generate(dayjs() + "")
await R.store(jwtSecretBean)
console.log("Stored JWT secret into database")
} else {
console.log("Load JWT secret from database.")
}
@@ -649,3 +681,72 @@ async function sendImportantHeartbeatList(socket, monitorID) {
socket.emit("importantHeartbeatList", monitorID, list)
}
const startGracefulShutdown = async () => {
console.log('Shutdown requested');
await (new Promise((resolve) => {
server.close(async function () {
console.log('Stopped Express.');
process.exit(0)
setTimeout(async () =>{
await R.close();
console.log("Stopped DB")
resolve();
}, 5000)
});
}));
}
let noReject = true;
process.on('unhandledRejection', (reason, p) => {
noReject = false;
});
async function shutdownFunction(signal) {
console.log('Called signal: ' + signal);
console.log("Stopping all monitors")
for (let id in monitorList) {
let monitor = monitorList[id]
monitor.stop()
}
await sleep(2000)
console.log("Closing DB")
// Special handle, because tarn.js throw a promise reject that cannot be caught
while (true) {
noReject = true;
await R.close()
await sleep(2000)
if (noReject) {
break;
} else {
console.log("Waiting...")
}
}
console.log("OK")
}
function finalFunction() {
console.log('Graceful Shutdown')
}
gracefulShutdown(server, {
signals: 'SIGINT SIGTERM',
timeout: 30000, // timeout: 30 secs
development: false, // not in dev mode
forceExit: true, // triggers process.exit() at the end of shutdown process
onShutdown: shutdownFunction, // shutdown function (async) - e.g. for cleanup DB, ...
finally: finalFunction // finally function (sync) - e.g. for logging
});

View File

@@ -56,7 +56,5 @@ exports.getSettings = async function (type) {
result[row.key] = row.value;
}
console.log(result)
return result;
}

View File

@@ -1,15 +1,11 @@
/*
* Common functions - can be used in frontend or backend
*/
// Common JS cannot be used in frontend sadly
// sleep, ucfirst is duplicated in ../src/util-frontend.js
export function sleep(ms) {
exports.sleep = function (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function ucfirst(str) {
exports.ucfirst = function (str) {
if (! str) {
return str;
}

View File

@@ -5,7 +5,7 @@
<script>
import {sleep} from "../../server/util";
import {sleep} from '../util-frontend'
export default {

View File

@@ -15,14 +15,14 @@
<label for="floatingPassword">Password</label>
</div>
<div class="form-check mb-3 mt-3" >
<label>
<div class="form-check mb-3 mt-3 d-flex justify-content-center pe-4">
<div class="form-check">
<input type="checkbox" value="remember-me" class="form-check-input" id="remember" v-model="$root.remember">
<label class="form-check-label" for="remember">
Remember me
</label>
</label>
</div>
</div>
<button class="w-100 btn btn-primary" type="submit" :disabled="processing">Login</button>

View File

@@ -10,56 +10,61 @@
</div>
<div class="modal-body">
<div class="mb-3">
<label for="type" class="form-label">Notification Type</label>
<select class="form-select" id="type" v-model="notification.type">
<option value="telegram">Telegram</option>
<option value="webhook">Webhook</option>
<option value="smtp">Email (SMTP)</option>
<option value="discord">Discord</option>
<option value="signal">Signal</option>
<option value="gotify">Gotify</option>
<option value="slack">Slack</option>
<option value="pushover">Pushover</option>
<option value="apprise">Apprise (Support 50+ Notification services)</option>
</select>
</div>
<div class="mb-3">
<label for="name" class="form-label">Friendly Name</label>
<input type="text" class="form-control" id="name" required v-model="notification.name">
</div>
<template v-if="notification.type === 'telegram'">
<div class="mb-3">
<label for="type" class="form-label">Notification Type</label>
<select class="form-select" id="type" v-model="notification.type">
<option value="telegram">Telegram</option>
<option value="webhook">Webhook</option>
<option value="smtp">Email (SMTP)</option>
<option value="discord">Discord</option>
</select>
<label for="telegram-bot-token" class="form-label">Bot Token</label>
<input type="text" class="form-control" id="telegram-bot-token" required v-model="notification.telegramBotToken">
<div class="form-text">You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.</div>
</div>
<div class="mb-3">
<label for="name" class="form-label">Friendly Name</label>
<input type="text" class="form-control" id="name" required v-model="notification.name">
<label for="telegram-chat-id" class="form-label">Chat ID</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="telegram-chat-id" required v-model="notification.telegramChatID">
<button class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID" v-if="notification.telegramBotToken">Auto Get</button>
</div>
<div class="form-text">
Support Direct Chat / Group / Channel's Chat ID
<p style="margin-top: 8px;">
You can get your chat id by sending message to the bot and go to this url to view the chat_id:
</p>
<p style="margin-top: 8px;">
<template v-if="notification.telegramBotToken">
<a :href="telegramGetUpdatesURL" target="_blank">{{ telegramGetUpdatesURL }}</a>
</template>
<template v-else>
{{ telegramGetUpdatesURL }}
</template>
</p>
</div>
</div>
<template v-if="notification.type === 'telegram'">
<div class="mb-3">
<label for="telegram-bot-token" class="form-label">Bot Token</label>
<input type="text" class="form-control" id="telegram-bot-token" required v-model="notification.telegramBotToken">
<div class="form-text">You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.</div>
</div>
<div class="mb-3">
<label for="telegram-chat-id" class="form-label">Chat ID</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="telegram-chat-id" required v-model="notification.telegramChatID">
<button class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID" v-if="notification.telegramBotToken">Auto Get</button>
</div>
<div class="form-text">
Support Direct Chat / Group / Channel's Chat ID
<p style="margin-top: 8px;">
You can get your chat id by sending message to the bot and go to this url to view the chat_id:
</p>
<p style="margin-top: 8px;">
<template v-if="notification.telegramBotToken">
<a :href="telegramGetUpdatesURL" target="_blank">{{ telegramGetUpdatesURL }}</a>
</template>
<template v-else>
{{ telegramGetUpdatesURL }}
</template>
</p>
</div>
</div>
</template>
</template>
<template v-if="notification.type === 'webhook'">
<div class="mb-3">
@@ -105,12 +110,12 @@
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" required v-model="notification.smtpUsername" autocomplete="false">
<input type="text" class="form-control" id="username" v-model="notification.smtpUsername" autocomplete="false">
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" required v-model="notification.smtpPassword" autocomplete="false">
<input type="password" class="form-control" id="password" v-model="notification.smtpPassword" autocomplete="false">
</div>
<div class="mb-3">
@@ -127,22 +132,167 @@
<template v-if="notification.type === 'discord'">
<div class="mb-3">
<label for="discord-token" class="form-label">Discord Bot Token</label>
<input type="text" class="form-control" id="discord-token" required v-model="notification.discordToken" autocomplete="false">
<div class="form-text">You should create a Discord app and create a bot from <a href="https://discord.com/developers/applications" target="_blank">here</a>.</div>
<label for="discord-webhook-url" class="form-label">Discord Webhook URL</label>
<input type="text" class="form-control" id="discord-webhook-url" required v-model="notification.discordWebhookUrl" autocomplete="false">
<div class="form-text">You can get this by going to Server Settings -> Integrations -> Create Webhook</div>
</div>
</template>
<template v-if="notification.type === 'signal'">
<div class="mb-3">
<label for="signal-url" class="form-label">Post URL</label>
<input type="url" pattern="https?://.+" class="form-control" id="signal-url" required v-model="notification.signalURL">
</div>
<div class="mb-3">
<label for="discordChannelID" class="form-label">Channel ID</label>
<input type="text" class="form-control" id="discordChannelID" required v-model="notification.discordChannelID" autocomplete="false">
<label for="signal-number" class="form-label">Number</label>
<input type="text" class="form-control" id="signal-number" required v-model="notification.signalNumber">
</div>
<div class="mb-3">
<label for="signal-recipients" class="form-label">Recipients</label>
<input type="text" class="form-control" id="signal-recipients" required v-model="notification.signalRecipients">
<div class="form-text">
You should add the bot to your channel. <br />
<a href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-" target="_blank">Where can I find the channel id?</a><br />
<a href="https://discordapi.com/permissions.html#8" target="_blank">How to add a bot to your channel?</a>
You need to have a signal client with REST API.
<p style="margin-top: 8px;">
You can check this url to view how to setup one:
</p>
<p style="margin-top: 8px;">
<a href="https://github.com/bbernhard/signal-cli-rest-api" target="_blank">https://github.com/bbernhard/signal-cli-rest-api</a>
</p>
<p style="margin-top: 8px;">
IMPORTANT: You cannot mix groups and numbers in recipients!
</p>
</div>
</div>
</template>
<template v-if="notification.type === 'gotify'">
<div class="mb-3">
<label for="gotify-application-token" class="form-label">Application Token</label>
<input type="text" class="form-control" id="gotify-application-token" required v-model="notification.gotifyapplicationToken">
</div>
<div class="mb-3">
<label for="gotify-server-url" class="form-label">Server URL</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="gotify-server-url" required v-model="notification.gotifyserverurl">
</div>
</div>
<div class="mb-3">
<label for="gotify-priority" class="form-label">Priority</label>
<input type="number" class="form-control" id="gotify-priority" v-model="notification.gotifyPriority" required min="0" max="10" step="1">
</div>
</template>
<template v-if="notification.type === 'slack'">
<div class="mb-3">
<label for="slack-webhook-url" class="form-label">Webhook URL<span style="color:red;"><sup>*</sup></span></label>
<input type="text" class="form-control" id="slack-webhook-url" required v-model="notification.slackwebhookURL">
<label for="slack-username" class="form-label">Username</label>
<input type="text" class="form-control" id="slack-username" v-model="notification.slackusername">
<label for="slack-iconemo" class="form-label">Icon Emoji</label>
<input type="text" class="form-control" id="slack-iconemo" v-model="notification.slackiconemo">
<label for="slack-channel" class="form-label">Channel Name</label>
<input type="text" class="form-control" id="slack-channel-name" v-model="notification.slackchannel">
<label for="slack-button-url" class="form-label">Uptime Kuma URL</label>
<input type="text" class="form-control" id="slack-button" v-model="notification.slackbutton">
<div class="form-text">
<span style="color:red;"><sup>*</sup></span>Required
<p style="margin-top: 8px;">
More info about webhooks on: <a href="https://api.slack.com/messaging/webhooks" target="_blank">https://api.slack.com/messaging/webhooks</a>
</p>
<p style="margin-top: 8px;">
Enter the channel name on Slack Channel Name field if you want to bypass the webhook channel. Ex: #other-channel
</p>
<p style="margin-top: 8px;">
If you leave the Uptime Kuma URL field blank, it will default to the Project Github page.
</p>
<p style="margin-top: 8px;">
Emoji cheat sheet: <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">https://www.webfx.com/tools/emoji-cheat-sheet/</a>
</p>
</div>
</div>
</template>
<template v-if="notification.type === 'pushover'">
<div class="mb-3">
<label for="pushover-app-token" class="form-label">Application Token<span style="color:red;"><sup>*</sup></span></label>
<input type="text" class="form-control" id="pushover-app-token" required v-model="notification.pushoverapptoken">
<label for="pushover-user" class="form-label">User Key<span style="color:red;"><sup>*</sup></span></label>
<input type="text" class="form-control" id="pushover-user" required v-model="notification.pushoveruserkey">
<label for="pushover-device" class="form-label">Device</label>
<input type="text" class="form-control" id="pushover-device" v-model="notification.pushoverdevice">
<label for="pushover-device" class="form-label">Message Title</label>
<input type="text" class="form-control" id="pushover-title" v-model="notification.pushovertitle">
<label for="pushover-priority" class="form-label">Priority</label>
<input type="text" class="form-control" id="pushover-priority" v-model="notification.pushoverpriority">
<label for="pushover-sound" class="form-label">Notification Sound</label>
<select class="form-select" id="pushover-sound" v-model="notification.pushoversounds">
<option>pushover</option>
<option>bike</option>
<option>bugle</option>
<option>cashregister</option>
<option>classical</option>
<option>cosmic</option>
<option>falling</option>
<option>gamelan</option>
<option>incoming</option>
<option>intermission</option>
<option>mechanical</option>
<option>pianobar</option>
<option>siren</option>
<option>spacealarm</option>
<option>tugboat</option>
<option>alien</option>
<option>climb</option>
<option>persistent</option>
<option>echo</option>
<option>updown</option>
<option>vibrate</option>
<option>none</option>
</select>
<div class="form-text">
<span style="color:red;"><sup>*</sup></span>Required
<p style="margin-top: 8px;">
More info on: <a href="https://pushover.net/api" target="_blank">https://pushover.net/api</a>
</p>
<p style="margin-top: 8px;">
Emergency priority(2) has default 30 second timeout between retries and will expire after 1 hour.
</p>
</div>
</div>
</template>
<template v-if="notification.type === 'apprise'">
<div class="mb-3">
<label for="gotify-application-token" class="form-label">Apprise URL</label>
<input type="text" class="form-control" id="gotify-application-token" required v-model="notification.appriseURL">
<div class="form-text">
<p>Example: twilio://AccountSid:AuthToken@FromPhoneNo</p>
<p>
Read more: <a href="https://github.com/caronc/apprise/wiki#notification-services" target="_blank">https://github.com/caronc/apprise/wiki#notification-services</a>
</p>
</div>
</div>
<div class="mb-3">
<p>
Status:
<span class="text-primary" v-if="appriseInstalled">Apprise is installed</span>
<span class="text-danger" v-else>Apprise is not installed. <a href="https://github.com/caronc/apprise">Read more</a></span>
</p>
</div>
</template>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button>
@@ -160,7 +310,7 @@
<script>
import { Modal } from 'bootstrap'
import { ucfirst } from "../../server/util";
import { ucfirst } from '../util-frontend'
import axios from "axios";
import { useToast } from 'vue-toastification'
import Confirm from "./Confirm.vue";
@@ -179,18 +329,17 @@ export default {
notification: {
name: "",
type: null,
gotifyPriority: 8
},
appriseInstalled: false,
}
},
mounted() {
this.modal = new Modal(this.$refs.modal)
// TODO: for edit
this.$root.getSocket().emit("getSettings", "notification", (data) => {
// this.notification = data
this.$root.getSocket().emit("checkApprise", (installed) => {
this.appriseInstalled = installed;
})
},
methods: {
@@ -218,6 +367,7 @@ export default {
// Default set to Telegram
this.notification.type = "telegram"
this.notification.gotifyPriority = 8
}
this.modal.show()

View File

@@ -9,7 +9,7 @@
<!-- Desktop header -->
<header class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom" v-if="! $root.isMobile">
<router-link to="/dashboard" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
<object class="bi me-2 ms-4" width="40" height="40" data="/icon.svg"></object>
<object class="bi me-2 ms-4" width="40" height="40" data="/icon.svg" alt="Logo"></object>
<span class="fs-4 title">Uptime Kuma</span>
</router-link>
@@ -33,6 +33,14 @@
<Login v-if="! $root.loggedIn && $root.allowLoginDialog" />
</main>
<footer>
<div class="container-fluid">
Uptime Kuma -
Version: {{ $root.info.version }} -
<a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">Check Update On GitHub</a>
</div>
</footer>
<!-- Mobile Only -->
<div style="width: 100%;height: 60px;" v-if="$root.isMobile"></div>
<nav class="bottom-nav" v-if="$root.isMobile">
@@ -130,6 +138,15 @@ export default {
}
main {
margin-bottom: 30px;
}
footer {
color: #AAA;
font-size: 13px;
margin-bottom: 30px;
margin-left: 10px;
text-align: center;
}
</style>

View File

@@ -9,6 +9,7 @@ export default {
data() {
return {
info: { },
socket: {
token: null,
firstConnect: true,
@@ -34,7 +35,8 @@ export default {
window.addEventListener('resize', this.onResize);
let wsHost;
if (localStorage.dev === "dev") {
const env = process.env.NODE_ENV || "production";
if (env === "development" || localStorage.dev === "dev") {
wsHost = ":3001"
} else {
wsHost = ""
@@ -44,6 +46,14 @@ export default {
transports: ['websocket']
});
socket.on("connect_error", (err) => {
console.error(`Failed to connect to the backend. Socket.io connect_error: ${err.message}`);
});
socket.on('info', (info) => {
this.info = info;
});
socket.on('setup', (monitorID, data) => {
this.$router.push("/setup")
});
@@ -153,7 +163,7 @@ export default {
},
getSocket() {
return socket;
return socket;
},
toastRes(res) {
@@ -280,6 +290,13 @@ export default {
watch: {
// Reload the SPA if the server version is changed.
"info.version"(to, from) {
if (from && from !== to) {
window.location.reload()
}
},
remember() {
localStorage.remember = (this.remember) ? "1" : "0"
}

View File

@@ -137,7 +137,7 @@ export default {
},
ping() {
if (this.lastHeartBeat.ping) {
if (this.lastHeartBeat.ping || this.lastHeartBeat.ping === 0) {
return this.lastHeartBeat.ping;
} else {
return "N/A"
@@ -145,7 +145,7 @@ export default {
},
avgPing() {
if (this.$root.avgPingList[this.monitor.id]) {
if (this.$root.avgPingList[this.monitor.id] || this.$root.avgPingList[this.monitor.id] === 0) {
return this.$root.avgPingList[this.monitor.id];
} else {
return "N/A"

View File

@@ -30,7 +30,7 @@
<div class="mb-3" v-if="monitor.type === 'keyword' ">
<label for="keyword" class="form-label">Keyword</label>
<input type="text" class="form-control" id="keyword" v-model="monitor.keyword" required>
<div class="form-text">Search keyword in plain html response and it is case-sensitive</div>
<div class="form-text">Search keyword in plain html or JSON response and it is case-sensitive</div>
</div>
<div class="mb-3" v-if="monitor.type === 'port' || monitor.type === 'ping' ">

View File

@@ -5,6 +5,19 @@ import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)
export function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function ucfirst(str) {
if (! str) {
return str;
}
const firstLetter = str.substr(0, 1);
return firstLetter.toUpperCase() + str.substr(1);
}
function getTimezoneOffset(timeZone) {
const now = new Date();
@@ -24,7 +37,6 @@ const aryIannaTimeZones = [
'Asia/Yerevan',
'Antarctica/Casey',
'Antarctica/Davis',
'Antarctica/DumontDUrville', // https://bugs.chromium.org/p/chromium/issues/detail?id=928068
'Antarctica/Mawson',
'Antarctica/Palmer',
'Antarctica/Rothera',
@@ -195,7 +207,6 @@ const aryIannaTimeZones = [
'Asia/Seoul',
'Asia/Almaty',
'Asia/Qyzylorda',
'Asia/Qostanay', // https://bugs.chromium.org/p/chromium/issues/detail?id=928068
'Asia/Aqtobe',
'Asia/Aqtau',
'Asia/Atyrau',
@@ -364,22 +375,29 @@ const aryIannaTimeZones = [
'Pacific/Efate',
'Pacific/Wallis',
'Pacific/Apia',
'Africa/Johannesburg'
'Africa/Johannesburg',
];
export function timezoneList() {
let result = [];
for (let timezone of aryIannaTimeZones) {
let display = dayjs().tz(timezone).format("Z");
try {
let display = dayjs().tz(timezone).format("Z");
result.push({
name: `(UTC${display}) ${timezone}`,
value: timezone,
time: getTimezoneOffset(timezone),
})
} catch (e) {
console.error(e.message);
console.log("Skip this timezone")
}
result.push({
name: `(UTC${display}) ${timezone}`,
value: timezone,
time: getTimezoneOffset(timezone),
})
}
result.sort((a, b) => {

View File

@@ -7,7 +7,7 @@ export default defineConfig({
plugins: [
vue(),
legacy({
targets: ['ie >= 11'],
targets: ['ie > 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime']
})
]