Compare commits

..

655 Commits

Author SHA1 Message Date
Louis Lam
7c13b1b6cb Update to 1.15.0-beta.1 2022-04-19 20:07:18 +08:00
Louis Lam
10f6a3c4f5 Merge pull request #1229 from Computroniks/#1209-Logout-button-in-navbar
Add #1209: logout button in navbar
2022-04-19 19:59:52 +08:00
Louis Lam
cd7c2beca6 Update CSS for dropdown menu 2022-04-19 19:46:21 +08:00
Louis Lam
8ee99760ec Minor lint 2022-04-19 19:41:52 +08:00
Louis Lam
cb55e23718 Add $root.username 2022-04-19 19:40:28 +08:00
Louis Lam
200fdfb808 Merge code manually since some code moved to another file 2022-04-19 16:46:45 +08:00
Louis Lam
29d2d95c71 Merge branch '1.14.X'
# Conflicts:
#	package.json
#	server/server.js
2022-04-19 16:43:13 +08:00
Louis Lam
b782b25e17 Update to 1.14.1 2022-04-19 16:01:08 +08:00
Louis Lam
919393cac9 Partially change the server core into a class, remove all require("./server") #1520 2022-04-19 15:38:59 +08:00
Louis Lam
17d4003e5c Add dropdown menu 2022-04-19 00:39:49 +08:00
Louis Lam
cefb5bb60a Merge branch 'master' into #1209-Logout-button-in-navbar 2022-04-18 20:39:24 +08:00
Louis Lam
9bf3b3a0f4 Update README.md 2022-04-18 19:15:50 +08:00
Louis Lam
e2c45f93bf Merge pull request #1509 from chakflying/feat/mqtt-optional-message
Feat: Allow MQTT successMessage to be optional
2022-04-18 19:06:39 +08:00
Louis Lam
addf75daa7 Fix MQTT password do not save 2022-04-18 19:05:14 +08:00
Louis Lam
359a490ae3 Fix #1510 2022-04-18 15:21:58 +08:00
Nelson Chan
cd38dd3f68 Feat: Allow MQTT successMessage to be optional 2022-04-18 13:04:55 +08:00
Louis Lam
f712fe85e5 Update node-sqlite, sqlite from 3.36 to 3.38 2022-04-18 12:44:32 +08:00
Louis Lam
c28b90feb4 Update to 1.15.0-beta.0 2022-04-17 20:07:32 +08:00
Louis Lam
ceba096f3e Merge pull request #875 from tarun7singh/master
Added MQTT Monitor type
2022-04-17 20:05:41 +08:00
Louis Lam
2a248ad73f Change mqtt_topic from VARCHAR to TEXT 2022-04-17 19:56:47 +08:00
Louis Lam
5fa62a888c Merge branch 'master' into mqtt2
# Conflicts:
#	server/database.js
#	server/util-server.js
2022-04-17 19:46:33 +08:00
Louis Lam
e6a8a84278 Include only nessacary data in webhook 2022-04-17 19:30:58 +08:00
Louis Lam
47c72192e1 [eslint] Enable yoda and eqeqeq 2022-04-17 15:43:03 +08:00
Louis Lam
d71c086447 Standardize array bracket spacing 2022-04-17 15:27:35 +08:00
Louis Lam
46e1a628a7 Update package-lock.json 2022-04-17 15:04:59 +08:00
Louis Lam
cd3dfd3146 Merge pull request #1083 from patrickhafner/customstatuspage
Custom status page
2022-04-17 15:04:02 +08:00
Louis Lam
572f2b9838 eslint 2022-04-17 14:57:31 +08:00
Louis Lam
8eb83394f7 Refine UI/UX for custom css / footer text. Add switch for show/hide powered by 2022-04-17 14:53:13 +08:00
Louis Lam
1bc01d1077 Merge branch 'master' into customstatuspage
# Conflicts:
#	src/languages/de-DE.js
2022-04-17 13:21:41 +08:00
Louis Lam
4e6ddc8880 Merge pull request #1497 from MrEddX/bulgarian
Bulgarian
2022-04-17 01:40:43 +08:00
Louis Lam
07c474db0b Merge remote-tracking branch 'origin/master' 2022-04-17 01:40:05 +08:00
Louis Lam
8d8c38b1a8 Allow unused vars in args and fix more eslint issues 2022-04-17 01:39:49 +08:00
Louis Lam
03bcf5c766 Add a simple mqtt server for testing 2022-04-17 01:07:54 +08:00
Louis Lam
136fdf3768 MQTT password field to password type 2022-04-17 01:07:36 +08:00
Louis Lam
e34420368b Remove try-catch and fix username/password/port not working for mqtt 2022-04-17 01:06:47 +08:00
Louis Lam
566133e350 Domain Name Expiry Notification for https monitor only 2022-04-16 15:01:53 +08:00
Louis Lam
30e113755e Add HIDE_LOG and catch error if cannot subscribe topic 2022-04-16 14:50:48 +08:00
Louis Lam
083e8355b7 Change debug to log.debug 2022-04-16 13:37:17 +08:00
Louis Lam
64a0e1aa9b Update package-lock.json 2022-04-16 13:31:40 +08:00
Louis Lam
b1c7915bc1 Merge branch 'master' into mqtt2
# Conflicts:
#	package-lock.json
#	package.json
#	server/database.js
#	server/model/monitor.js
#	server/server.js
#	src/pages/EditMonitor.vue
2022-04-16 13:28:39 +08:00
Louis Lam
b7aebceaab Update bg-BG.js 2022-04-15 19:49:16 +08:00
MrEddX
0302fdbc96 Update bg-BG.js
Status pages - fix
2022-04-15 13:10:14 +03:00
MrEddX
84a50f058f Update bg-BG.js 2022-04-15 13:06:22 +03:00
MrEddX
9ec652639b Merge branch 'louislam:master' into bulgarian 2022-04-15 13:03:34 +03:00
Louis Lam
0c40e32d75 Merge pull request #1007 from chakflying/feat/save-chart-period
Feat: Save and restore chart period
2022-04-15 12:34:53 +08:00
Nelson Chan
6f99d7577b Fix: Limit saved period & clear when set to recent 2022-04-15 03:24:58 +08:00
Nelson Chan
1417b6eacf Feat: Save and restore chart period 2022-04-15 02:56:21 +08:00
MrEddX
1baee42cf5 Merge branch 'louislam:master' into bulgarian 2022-04-14 10:55:04 +03:00
Louis Lam
fb0064082e Change Pushdeer to PushDeer 2022-04-14 14:34:30 +08:00
ngc7331
93c51504f9 fixes: formatting and security issues
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2022-04-14 14:34:30 +08:00
ngc7331
fb059f5e91 Add support for Pushdeer notifications 2022-04-14 14:34:30 +08:00
PhyxionNL
2e3414135f Update src/components/PingChart.vue
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2022-04-14 12:27:38 +08:00
PhyxionNL
e44699216e Fix readability of chart hover 2022-04-14 12:27:38 +08:00
DX37
fd8cba1dad nudge nodemailer strings; translate new ones 2022-04-14 11:10:24 +08:00
sovushik
03dd02fd38 Update ru-RU.js
Add RU for 1.14 version
2022-04-14 11:04:46 +08:00
Louis Lam
d0b5f147e2 Fix spelling and merge mistake 2022-04-14 10:58:28 +08:00
Louis Lam
ddf8a7a692 Fix camelCase 2022-04-14 10:58:28 +08:00
ColdThunder11
bd9df09f87 Apply suggestions from code review, fix style
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2022-04-14 10:58:28 +08:00
ColdThunder11
4656ab3d57 Add OneBot notification service 2022-04-14 10:58:28 +08:00
Louis Lam
0a5db0cecb Fix #1478 2022-04-14 10:12:31 +08:00
MrEddX
60b44c2cdd Update bg-BG.js
Fixed translation.
2022-04-14 09:46:43 +08:00
MrEddX
16b61dba27 Merge branch 'louislam:master' into bulgarian 2022-04-13 21:59:53 +03:00
Louis Lam
2b0c184a88 Update package-lock 2022-04-14 01:21:43 +08:00
Louis Lam
2642e70fc8 Fix auto test failed due to autocrlf 2022-04-14 01:20:54 +08:00
Louis Lam
8d0446dc38 Add lint as part of test 2022-04-14 01:20:54 +08:00
Louis Lam
3436e26ed4 Fix styleline, fix css format issues globally 2022-04-14 01:20:54 +08:00
Louis Lam
649f3106e1 Enforce semicolon, fix format globally 2022-04-14 01:20:54 +08:00
Louis Lam
6f72ca481f Merge pull request #1479 from AnnAngela/1.14.0_translation
New translation for zh-CN
2022-04-14 00:05:07 +08:00
Louis Lam
670ea415b2 Merge pull request #1488 from c0derMo/update-german-translation
updating german translation
2022-04-14 00:03:53 +08:00
Louis Lam
17dcf6d3a2 Merge pull request #910 from andreasbrett/logging
introduce consistent logging
2022-04-13 23:47:08 +08:00
Louis Lam
e9ce1433cd Change log_info to log.info by making it into an object 2022-04-13 23:33:37 +08:00
c0derMo
f5d006add8 updating german translation 2022-04-13 14:45:41 +00:00
Louis Lam
4df147786d Merge pull request #1483 from Alexandre-Gliganic/master
Add automatic restart for docker-compose.yml
2022-04-12 22:39:29 +08:00
Alexandre Gliganic
27861f0d14 Add automatic restart docker-compose.yml 2022-04-12 16:09:01 +02:00
AnnAngela-work
5aa747a301 New translation 2022-04-12 20:41:25 +08:00
Louis Lam
81de2eedfb Fix template can contain one tag only, disable vue/require-component-is eslint rule 2022-04-12 20:23:11 +08:00
Louis Lam
4a6d7207ef Merge branch 'master' into customstatuspage
# Conflicts:
#	src/languages/de-DE.js
#	src/languages/en.js
#	src/pages/StatusPage.vue
2022-04-12 19:39:42 +08:00
Louis Lam
4053b9db1f Merge remote-tracking branch 'origin/master' 2022-04-12 17:46:24 +08:00
Louis Lam
772d009f43 Merge branch 'master' into fluencydoc_master
# Conflicts:
#	extra/update-version.js
#	server/client.js
#	server/server.js
2022-04-12 17:44:04 +08:00
MrEddX
ae54d9c011 Merge branch 'louislam:master' into bulgarian 2022-04-12 12:37:52 +03:00
Louis Lam
5ca606fe99 Merge pull request #1141 from marcules/issue/1138
Issue/1138
2022-04-12 17:32:52 +08:00
Louis Lam
6179f6c982 Merge branch 'master' into issue/1138
# Conflicts:
#	server/server.js
2022-04-12 17:15:33 +08:00
Louis Lam
94770cf865 Resolve log message null reference 2022-04-12 16:57:22 +08:00
Louis Lam
9ec29c1bc4 Add back debug() for safe, but it is marked as deprecated 2022-04-12 16:37:05 +08:00
Louis Lam
279e2eb3f6 Merge branch 'master' into logging
# Conflicts:
#	server/database.js
#	server/jobs.js
#	server/model/monitor.js
#	server/routers/api-router.js
#	server/server.js
#	server/socket-handlers/status-page-socket-handler.js
#	server/util-server.js
2022-04-12 16:32:14 +08:00
Louis Lam
1ba92d803e Update to 1.14.0 2022-04-12 14:17:13 +08:00
Louis Lam
45ca3085b2 Update CONTRIBUTING.md 2022-04-12 13:53:52 +08:00
Louis Lam
a0d1ae2cce Better alignment of monitor list item 2022-04-11 18:02:18 +08:00
Louis Lam
f030487f7d Fix theme color that do not apply to status page with a custom domain 2022-04-10 13:46:00 +08:00
Louis Lam
316e65d35a Update to 1.14.0-beta.2 2022-04-10 00:46:34 +08:00
Louis Lam
df5ba02f3f Merge pull request #1415 from louislam/status-page-domain
[Status Page] Map domain names to status pages
2022-04-10 00:42:31 +08:00
Louis Lam
c9fa183712 Manage domain names 2022-04-10 00:25:27 +08:00
Louis Lam
0b9b5102ec Minor 2022-04-09 17:23:22 +08:00
Louis Lam
c399984b7f Improve status page sidebar 2022-04-09 17:03:10 +08:00
Louis Lam
0afa0be5c2 Merge branch 'master' into status-page-domain
# Conflicts:
#	server/database.js
2022-04-09 16:07:09 +08:00
Louis Lam
6a30dbd71a Fix Mattermost when channel is empty #1468 2022-04-09 15:44:50 +08:00
Louis Lam
a2d9474e85 Copy some keys from zh-TW to zh-HK 2022-04-09 14:51:26 +08:00
Louis Lam
8479e772cd Merge pull request #1463 from JohnnyChiang/update-zh-TW-translation
Update zh-TW translation
2022-04-09 14:44:44 +08:00
Louis Lam
2e50ef0e8f Merge pull request #1450 from AnnAngela/1.14.0-zh_cn
1.14.0 translation improvement
2022-04-09 14:40:38 +08:00
Louis Lam
4fb2c69dd1 Merge pull request #1461 from louislam/proxy-improvement
Proxy Improvements
2022-04-09 13:54:28 +08:00
Louis Lam
c08910a65c Update README.md 2022-04-08 19:45:39 +08:00
Louis Lam
943c904256 Update docker-compose.yml 2022-04-08 19:43:51 +08:00
JohnnyChiang
25b5edea7f Update zh-TW translation 2022-04-08 01:47:01 +08:00
Louis Lam
7bbaeffd3e Fix reset-password (issue caused by 5027fcd320) 2022-04-08 00:56:56 +08:00
Louis Lam
008dc27f52 Reload proxy settings for monitors in the monitorList 2022-04-07 23:03:45 +08:00
Louis Lam
5027fcd320 Export server using an object class 2022-04-07 23:02:57 +08:00
Louis Lam
d5e68f8453 Export monitor list 2022-04-07 22:53:32 +08:00
Louis Lam
fcb577097b [Proxy] Change to radio button 2022-04-07 15:26:00 +08:00
Louis Lam
082c2dd32d Remove restartMonitors() and move proxy socket events to a socket handler file 2022-04-07 14:45:37 +08:00
Louis Lam
e89356b283 Show proxy option for http monitor only 2022-04-07 14:37:33 +08:00
Louis Lam
6014b9534f Merge remote-tracking branch 'origin/master' 2022-04-06 23:20:40 +08:00
Louis Lam
8b45a95cc3 Merge branch '1.13.X'
# Conflicts:
#	package.json
2022-04-06 23:20:22 +08:00
Louis Lam
02becfd113 Update to 1.13.2 2022-04-06 22:54:03 +08:00
Louis Lam
8ad992eac8 Fix setup issue when using npm 8.6.0 2022-04-06 22:50:21 +08:00
Louis Lam
c4e74c9943 Render <StatusPage> if domain matched 2022-04-06 22:43:22 +08:00
Louis Lam
fee88b32e3 Set PRAGMA synchronous = FULL 2022-04-06 20:48:13 +08:00
Louis Lam
ffc5bca51d Update required tools' links 2022-04-06 13:18:12 +08:00
AnnAngela
511b9dd425 Update fs-rmSync.js 2022-04-06 10:31:01 +08:00
AnnAngela
e9dd64b6f0 Update comments of fs-rmSync.js 2022-04-06 10:20:57 +08:00
Louis Lam
355aec46dc Merge branch 'master' into status-page-domain 2022-04-05 22:59:39 +08:00
Louis Lam
c9deea9fdf Merge pull request #1456 from Arubinu/alerta
Fix "API key parameter 'undefined' is invalid"
2022-04-05 22:51:33 +08:00
Louis Lam
70311f7a5a Add an option to enable/disable the domain name expiry notification #1364 2022-04-05 21:27:50 +08:00
Louis Lam
4b99160b1f Fix "Check Update" is not checked by default 2022-04-05 19:43:23 +08:00
Louis Lam
48d679234a Stop bree and cloudflared while the server shutting down 2022-04-05 19:41:29 +08:00
Louis Lam
d8b32d652f Update .dockerignore 2022-04-05 16:44:55 +08:00
Alvin Pergens
d3d1656625 Fix "API key parameter 'undefined' is invalid" 2022-04-05 08:47:35 +02:00
AnnAngela-work
8e78e62eee Make translation better 2022-04-04 17:24:22 +08:00
AnnAngela
706d6cee07 Update some components to use i18n function, update en & zh-CN translation 2022-04-04 11:33:02 +08:00
AnnAngela-work
43eed45bae first part of zh-CN.js translation 2022-04-03 22:08:24 +08:00
AnnAngela-work
19b7e2ba5e Using grep to search $t("foo")-like pattern to fill up the missing part of en i18n file 2022-04-03 22:08:03 +08:00
Louis Lam
99042e6991 Update to 1.14.0-beta.1 2022-04-03 22:06:39 +08:00
Louis Lam
f54084c888 Update beta release process 2022-04-03 22:06:36 +08:00
Louis Lam
87d3853b8e Merge pull request #1348 from AnnAngela/master
Detect if `fs.rmSync` is available to avoid the runtime deprecation warning
2022-04-02 18:21:12 +08:00
Louis Lam
4738581c66 Update dependencies 2022-04-02 11:34:00 +08:00
Louis Lam
3218a0eee8 Merge remote-tracking branch 'origin/master' 2022-04-02 11:26:24 +08:00
Louis Lam
87ee3c20bd Update proxy password field 2022-04-02 11:25:27 +08:00
Louis Lam
38e6e846bf Refresh sponsor list 2022-04-01 23:22:15 +08:00
Louis Lam
92ab2b12d0 Refresh sponsor list 2022-04-01 17:37:04 +08:00
Louis Lam
04e3394d02 Merge branch 'master' into feature/request-with-http-proxy
# Conflicts:
#	package-lock.json
#	package.json
#	server/database.js
#	src/languages/en.js
#	src/mixins/socket.js
2022-04-01 14:57:35 +08:00
Louis Lam
f6cd2f60ca Merge pull request #1442 from BCsabaEngine/master
fix: update hu lang
2022-04-01 14:46:56 +08:00
Balázs Csaba
53cea7f8d3 fix: update hu lang 2022-03-31 22:25:22 +02:00
Louis Lam
aef7719426 Merge pull request #1435 from LoaderB0T/favico
feat: Favicon is updated based on satus page logo
2022-03-31 21:32:13 +08:00
Louis Lam
514b9fb68a Add remark 2022-03-31 21:30:07 +08:00
Louis Lam
da32a1aa19 Add uk-UA to the languageList 2022-03-31 16:24:28 +08:00
Louis Lam
7a69f9f56f Merge pull request #1438 from Deni7/master
Add ukrainian translation
2022-03-31 16:22:29 +08:00
Louis Lam
c50c20faa4 Minor fix for uk-UA 2022-03-31 16:19:04 +08:00
Louis Lam
cb6eeaef34 Bring connection error bar to the top 2022-03-31 16:15:34 +08:00
Louis Lam
6674005e8b Fix storing cloudflared token while start cloudflared 2022-03-31 15:58:39 +08:00
Denis Stepanov
ee3d7d8b42 Add ukrainian translation 2022-03-30 23:21:09 +03:00
Denis Stepanov
a277cfe9e8 Add ukrainian translation 2022-03-30 23:16:04 +03:00
Denis Stepanov
95b0df0270 Add ukrainian translation 2022-03-30 23:15:28 +03:00
Louis Lam
f02e9c44ec Update to 1.14.0-beta.0 2022-03-30 23:37:23 +08:00
Louis Lam
bb2b5cd6ac Merge pull request #1427 from louislam/cloudflared
Built-in ease-to-use reverse proxy with Cloudflare Tunnel
2022-03-30 20:15:48 +08:00
Louis Lam
b72a2d350f Set cloudflared token from env var or arg 2022-03-30 20:08:26 +08:00
Louis Lam
71be030733 Add package-lock.json and minor words 2022-03-30 18:52:10 +08:00
Janik Schumacher
73b338bba6 feat: Favicon is updated based on satus page logo 2022-03-30 12:09:38 +02:00
Louis Lam
82ea896bbc Improve the workflow of cloudflared 2022-03-30 11:59:49 +08:00
Louis Lam
f1f4b3b377 Add reverse proxy setting page for controlling cloudflared 2022-03-30 01:49:45 +08:00
Louis Lam
a6b52b7ba6 Merge branch 'master' into cloudflared 2022-03-29 17:42:55 +08:00
Louis Lam
b8dea3a823 Merge remote-tracking branch 'origin/master' 2022-03-29 17:39:12 +08:00
Louis Lam
0da6e6b1fb Some improvements 2022-03-29 17:38:48 +08:00
Louis Lam
44fb2a88f2 Add cloudflared socket handler 2022-03-29 14:48:02 +08:00
Louis Lam
623b06e33c Merge pull request #1426 from DX37/translation-ru
update russian translation
2022-03-29 14:14:21 +08:00
Louis Lam
7d3cbff794 [Cloudflared] Install into base docker 2022-03-29 02:24:10 +08:00
DX37
61d0a0abce update russian translation 2022-03-28 21:16:13 +07:00
AnnAngela
7fd5b61bab Inproperly conflict resolving 2022-03-27 21:12:51 +08:00
AnnAngela
96289fe014 Update index.js 2022-03-27 20:56:42 +08:00
AnnAngela
381605aca1 Update update-version.js 2022-03-27 20:55:28 +08:00
AnnAngela
742c6bcaa3 Merge branch 'master' into master 2022-03-27 20:54:24 +08:00
Matthew Nickson
88604845e6 Merge branch 'master' into #1209-Logout-button-in-navbar 2022-03-27 13:48:50 +01:00
Louis Lam
be88351eb3 Merge pull request #1136 from chakflying/fix/prometheus-on-delete
Fix: Remove prometheus metrics on delete [Test needed]
2022-03-27 11:05:50 +08:00
Louis Lam
34a0b54b93 Merge pull request #1418 from sovushik/patch-11
Update ru-RU.js
2022-03-26 14:11:32 +08:00
sovushik
e11ea7b061 Update ru-RU.js
Add new string for 1.13.1
2022-03-26 10:46:07 +05:00
Louis Lam
12237dec6e Merge remote-tracking branch 'origin/master' 2022-03-26 02:09:25 +08:00
Louis Lam
f6272155af Show page not found for invalid routes 2022-03-26 02:09:12 +08:00
Louis Lam
630b441a2d Merge pull request #1414 from ivanbratovic/croatian-language
Update croatian (hr-HR) translation file
2022-03-25 19:00:06 +08:00
Louis Lam
1ecd2e45d0 [Status Page] Plan to support domain names for status pages 2022-03-25 18:59:06 +08:00
Ivan Bratović
5922771909 Update croatian (hr-HR) translation file
Signed-off-by: Ivan Bratović <ivanbratovic4@gmail.com>
2022-03-25 11:05:51 +01:00
MrEddX
a7e1a78ea9 Update bg-BG.js
Fixed translation.
2022-03-25 07:31:26 +02:00
Louis Lam
623d03dc6f Fix release process 2022-03-25 00:03:25 +08:00
Louis Lam
f52e527850 Update to 1.13.1 2022-03-24 23:47:03 +08:00
Louis Lam
28d72fcd08 Fix #1409, slug cannot be empty 2022-03-24 23:43:07 +08:00
Louis Lam
6c7a0ff7d3 Fix release script 2022-03-24 22:44:22 +08:00
Louis Lam
2abdf2efad Update to 1.13.0 2022-03-24 22:21:19 +08:00
Louis Lam
71af08189e Clear useless code 2022-03-24 18:03:31 +08:00
Louis Lam
d32ba7cadd Fix #1318, basic auth is completely disabled if the auth is disabled 2022-03-24 18:02:34 +08:00
Louis Lam
775d1696fa Fix pushover device not working #1114 2022-03-24 12:14:17 +08:00
Louis Lam
7fb16d2f9a Limit the pm2 log size 2022-03-23 11:17:23 +08:00
Louis Lam
40991fbc28 Show reverse proxy guide along with websocket error 2022-03-22 23:46:13 +08:00
Louis Lam
bf20f9d290 Merge remote-tracking branch 'origin/master' 2022-03-22 21:37:18 +08:00
Louis Lam
5fa14161c4 Minor css 2022-03-22 21:37:04 +08:00
Louis Lam
5a2a59250d Merge pull request #1405 from sovushik/patch-9
Update ru-RU.js
2022-03-22 17:17:37 +08:00
Louis Lam
fcee93cbea Merge pull request #1404 from sovushik/patch-8
Update ru-RU.js
2022-03-22 17:16:55 +08:00
Louis Lam
668dffc2c5 Simplify final release 2022-03-22 16:45:07 +08:00
sovushik
210eebe144 Update ru-RU.js
Add some fix for 1.13
2022-03-22 13:00:16 +05:00
sovushik
4b04a9c214 Update ru-RU.js
Add new string for version 1.13
2022-03-22 12:58:38 +05:00
Louis Lam
909618a29a Update to 1.13.0-beta.2 2022-03-22 14:30:54 +08:00
Louis Lam
4a4ffc96dd Fix setup 2022-03-22 12:00:13 +08:00
Louis Lam
3713692bdd Merge remote-tracking branch 'origin/master' 2022-03-22 11:31:01 +08:00
Louis Lam
76f991ecd8 Update beta process 2022-03-22 11:30:45 +08:00
Louis Lam
84dcd81f21 Merge pull request #1400 from MrEddX/bulgarian
Update bg-BG.js
2022-03-22 10:50:59 +08:00
MrEddX
f65d0654a6 Update bg-BG.js
Added new field.
2022-03-21 21:12:15 +02:00
Louis Lam
b0bda9f9d2 Fix beta release script 2022-03-22 01:00:35 +08:00
Louis Lam
ad2130b7b5 [Status Page] Fix monitors are deleted unexpectedly #1399 2022-03-22 00:06:29 +08:00
Louis Lam
4545eec3fe Better sticky monitor list 2022-03-21 23:53:55 +08:00
Louis Lam
3adda48f3a Load the status page list earlier 2022-03-21 15:28:59 +08:00
Louis Lam
cafa61e3af Add beta tag 2022-03-21 14:32:55 +08:00
Louis Lam
58ee071fae Release process for beta 2022-03-21 14:31:29 +08:00
Louis Lam
9173838e1b Merge remote-tracking branch 'origin/master' 2022-03-21 11:50:27 +08:00
Louis Lam
833d9381ff Merge pull request #1393 from burakurer/patch-1
Update tr-TR.js
2022-03-21 11:50:17 +08:00
burakurer
73d904952d Update tr-TR.js
spelling correction "Sağlık Dırımları" => "Sağlık Durumları"
2022-03-20 17:03:32 +03:00
Louis Lam
4e95e9ea51 Add process for beta release 2022-03-20 11:08:33 +08:00
Louis Lam
c22cc4d794 Merge pull request #1385 from jtagcat/patch-1
Update et-EE.js
2022-03-20 10:56:24 +08:00
Louis Lam
8cbdefdc0d Merge pull request #1390 from pemassi/patch-3
Update ko-KR.js
2022-03-20 10:55:51 +08:00
Kyungyoon Kim
2f5beefa37 Update ko-KR.js 2022-03-19 03:19:02 -06:00
jtagcat
dae5ff690a Update et-EE.js 2022-03-18 13:56:45 +00:00
Louis Lam
fb9a206542 [Status Page] Fix - show no status page 2022-03-18 21:47:14 +08:00
jtagcat
dc3da45dd6 Update et-EE.js 2022-03-18 11:27:33 +00:00
Louis Lam
82049a2387 Merge pull request #863 from louislam/restructure-status-page
Restructure status page core implementation
2022-03-18 18:07:15 +08:00
Louis Lam
d7a839aa52 [Status Page] Fix reset entry page 2022-03-18 17:57:08 +08:00
Louis Lam
aef0a66205 [Status Page] Simplify show tags logic 2022-03-18 17:56:46 +08:00
Louis Lam
37be7df9b0 [Status Page] Delete status page 2022-03-18 15:19:52 +08:00
Louis Lam
243fab5f26 Rollback vite to 2.6.x (Not sure, but sometimes vue routes are no longer response during dev randomly) 2022-03-18 15:02:49 +08:00
Louis Lam
8d981c8f0b [Status Page] Fix migration and unpin incident 2022-03-18 14:14:22 +08:00
Louis Lam
220e46bc83 [Status Page] Fix theme bug 2022-03-18 12:57:37 +08:00
Louis Lam
59cdacc052 [Status Page] Enable Edit Mode only if the token is presented 2022-03-18 12:39:48 +08:00
Louis Lam
00738edbe7 [Status Page] Add ?edit 2022-03-18 00:00:56 +08:00
Louis Lam
27bfae67af [Status Page] Add a new status page 2022-03-17 23:38:43 +08:00
Louis Lam
719a136d1e [Status Page] Improved entry page 2022-03-17 22:44:47 +08:00
Louis Lam
502c7f87e7 [Status Page] Listing: Better loading effect 2022-03-17 19:07:05 +08:00
Louis Lam
78a732409b [Status Page] Fix translations 2022-03-17 18:56:59 +08:00
Louis Lam
c0c6419980 [Status Page] align icon and title using flexbox 2022-03-17 17:07:23 +08:00
Louis Lam
5474368263 Update vite to 2.8.6 2022-03-17 16:56:25 +08:00
Louis Lam
e87cdf4d09 [Status Page] wip, upload logo and status page listing 2022-03-17 16:42:26 +08:00
Louis Lam
bb1c951a96 Update node.js from 14 to 16 2022-03-17 13:04:43 +08:00
Louis Lam
1033ca5cf4 [Status Page] wip, combine api, add status_page_id into group and incident tables 2022-03-16 15:38:10 +08:00
Louis Lam
18ec42b060 [Status Page] wip 2022-03-16 14:14:47 +08:00
Louis Lam
7c7dbf68c1 [Status Page] wip, sidebar for editor 2022-03-15 12:00:29 +08:00
Louis Lam
3e96504813 Update denpendencies 2022-03-13 17:14:57 +08:00
Louis Lam
d765b1c57a Merge branch 'master' into restructure-status-page
# Conflicts:
#	src/pages/StatusPage.vue
2022-03-12 15:50:42 +08:00
Louis Lam
5f778b9763 Merge pull request #835 from willianrod/feat/add-favicon-badges
Add badges to favicon
2022-03-12 15:39:18 +08:00
Louis Lam
c68f7944e3 [Favicon] minor 2022-03-12 15:31:01 +08:00
Louis Lam
a9efdabcec [Favicon] Prevent error when no heartbeat 2022-03-12 15:30:02 +08:00
Louis Lam
b9dfcd1291 [Favicon] Code refactoring 2022-03-12 15:10:45 +08:00
Louis Lam
04d93c2747 Merge branch 'master' into willianrod_feat/add-favicon-badges
# Conflicts:
#	package-lock.json
#	src/mixins/socket.js
2022-03-12 11:17:32 +08:00
Louis Lam
c65d771fad Merge pull request #1358 from BCsabaEngine/master
fix: .hu lang
2022-03-12 10:38:37 +08:00
Louis Lam
3f8a396090 Merge pull request #1362 from MrEddX/bulgarian
Bulgarian
2022-03-12 10:37:46 +08:00
Louis Lam
9681957adf Merge pull request #1366 from deanilvincent/update-version-of-check-password-strength
check-password-strength new version update 2.0.5
2022-03-12 10:25:06 +08:00
Mark Vicente
95a2c967c6 check-password-strength new version 2.0.5 that support additional symbols/special characters referenced from owasp list. 2022-03-11 23:48:35 +08:00
Louis Lam
50d6e888c2 [new status page] wip 2022-03-10 21:34:30 +08:00
Louis Lam
ae14ad5a84 Add a word "Status Pages" 2022-03-09 22:14:07 +08:00
MrEddX
edd9202de9 Update bg-BG.js
Translation fix.
2022-03-08 22:14:07 +02:00
MrEddX
a97d2a5498 Update bg-BG.js
Added new fields.
2022-03-08 22:10:17 +02:00
Louis Lam
72ce28a541 Migrate status page table 2022-03-08 14:33:35 +08:00
Louis Lam
1e2a8453c6 Merge branch 'master' into restructure-status-page 2022-03-08 14:21:04 +08:00
Louis Lam
1fa4a16663 Check beta release 2022-03-07 16:24:24 +08:00
Louis Lam
6a57c443fd Set telegram as the default notification type 2022-03-07 15:52:17 +08:00
Uğur Erkan
8078d0618d Add socks proxy support to proxy feature
- Socks proxy support implemented.
- Monitor proxy agent create flow refactored
  and moved under proxy class.

Thanks for suggestion @thomasleveil
2022-03-06 19:34:51 +03:00
Uğur Erkan
9e27acb511 Add socks proxy agent 2022-03-06 19:34:51 +03:00
Uğur Erkan
78d76512ba Add http and https proxy feature
Added new proxy feature based on http and https proxy agents.
Proxy feature works like notifications, there is many proxy
could be related one proxy entry.

Supported features
- Proxies can activate and disable in bulk
- Proxies auto enabled by default for new monitors
- Proxies could be applied in bulk to current monitors
- Both authenticated and anonymous proxies supported
- Export and import support for proxies
2022-03-06 19:34:49 +03:00
Uğur Erkan
2cc7a990ff Add http and https agents 2022-03-06 19:29:28 +03:00
Balázs Csaba
157f0de61a fix: .hu lang 2022-03-05 21:24:50 +01:00
Louis Lam
88c3d952d3 Improve settings page's UI/UX on mobile 2022-03-04 23:20:42 +08:00
Louis Lam
e3a0eaf6af Sort notification types in case-insensitive 2022-03-04 21:48:35 +08:00
Louis Lam
8bbf55777e Merge pull request #1205 from arjunkomath/master
Add notification provider - Push
2022-03-04 21:39:59 +08:00
Louis Lam
c0e0698c21 Merge pull request #1225 from Computroniks/fix-checkbox-css
Fixed dark mode checkbox
2022-03-04 14:35:15 +08:00
Louis Lam
14d8095f12 Merge pull request #1228 from Arubinu/alerta
Alerta Notification Service
2022-03-04 14:19:53 +08:00
Louis Lam
fa490d0bf1 [Alerta] Handle general message 2022-03-04 14:13:44 +08:00
Louis Lam
c52c8a4206 Merge branch 'master' into alerta
# Conflicts:
#	server/notification.js
#	src/components/notifications/index.js
#	src/languages/en.js
2022-03-04 14:10:37 +08:00
Louis Lam
9789d8cde8 Merge branch 'master' into alerta 2022-03-04 14:09:01 +08:00
Louis Lam
ccb3d85a48 Merge pull request #1157 from zackelia/master
Implement gorush notifications
2022-03-03 22:03:09 +08:00
Louis Lam
333505b039 Merge remote-tracking branch 'origin/master' 2022-03-03 20:49:13 +08:00
Louis Lam
602da565eb Sort notification types 2022-03-03 20:49:00 +08:00
Louis Lam
b62d94184a Merge branch 'master' into restructure-status-page 2022-03-03 17:09:15 +08:00
Louis Lam
e0175d0010 Delete stale-bot.yml, no idea why it deleted some feature request 2022-03-03 10:21:34 +08:00
Louis Lam
3246055696 Merge pull request #1350 from deluxghost/patch-1
Update zh-CN.js
2022-03-02 23:20:47 +08:00
deluxghost
b3a690f3b1 Update zh-CN.js 2022-03-02 23:12:30 +08:00
Louis Lam
7bc8c447cd Merge branch 'MikMuellerDev_master'
# Conflicts:
#	src/languages/de-DE.js
2022-03-02 17:17:15 +08:00
Louis Lam
69ff6831ab Merge pull request #1311 from deluxghost/update-zh-cn
Update zh-CN translations
2022-03-02 16:58:54 +08:00
AnnAngela
88a798704b Update fs-rmSync.js 2022-03-02 16:10:14 +08:00
AnnAngela-work
783173fd1f Add a helper function 2022-03-02 15:48:08 +08:00
DX
0dba06e48b Update zh-CN translations 2022-03-02 15:34:11 +08:00
AnnAngela-work
281fe365c0 Mark the version as 1.11.4 in package-lock.json 2022-03-02 15:23:08 +08:00
Louis Lam
8e7c0a6163 Update pull request rules 2022-03-02 14:25:37 +08:00
Louis Lam
0671e4ea2b Merge remote-tracking branch 'AnnAngela/master'
# Conflicts:
#	src/languages/zh-CN.js
2022-03-02 13:43:34 +08:00
Louis Lam
cd8eaef903 Merge pull request #1187 from pfandie/translations-de
Updates some DE translations
2022-03-02 13:39:19 +08:00
Louis Lam
51f5c009e3 Merge remote-tracking branch 'PrikolMen/patch-1'
# Conflicts:
#	src/languages/ru-RU.js
2022-03-02 13:37:21 +08:00
Louis Lam
3bf62c9ceb Merge branch 'patch-7-ru'
# Conflicts:
#	src/languages/ru-RU.js
2022-03-02 13:33:37 +08:00
Louis Lam
7b11539cff Merge branch 'patch-62'
# Conflicts:
#	src/languages/ru-RU.js
2022-03-02 13:31:43 +08:00
PrikolMen:-b
b4a3d68356 More correct Russian translation
I tried to fix most of the shortcomings of the Russian translation...
2022-02-28 14:55:23 +04:00
Louis Lam
b31af8a15c update to 1.12.1 2022-02-26 17:05:13 +08:00
Louis Lam
60f67ccb35 Revert commit: a6fd626f 2022-02-26 16:57:13 +08:00
Louis Lam
81a9807a0a Update release procedures 2022-02-26 16:03:43 +08:00
Louis Lam
3681934d05 Update Apprise to 0.9.7 2022-02-26 15:57:26 +08:00
Louis Lam
d5d63474d8 update to 1.12.0 2022-02-26 15:41:32 +08:00
Louis Lam
a6fd626fb8 Locked Russian language, ask Putin to stop the war and unlock it 2022-02-26 14:56:57 +08:00
Louis Lam
3a5b413af4 Update axios to 0.26.0 due to vulnerability 2022-02-26 14:36:38 +08:00
Louis Lam
595cd93220 Check invalid interval 2022-02-24 15:11:17 +08:00
Louis Lam
e12c1511db Merge pull request #1330 from BCsabaEngine/master
fix: hu lang
2022-02-23 22:36:05 +08:00
Balázs Csaba
f3112c0b85 fix: hu lang 2022-02-23 09:35:56 +01:00
Louis Lam
af07850ddf Merge pull request #1287 from sovushik/patch-5
Update ru-RU.js
2022-02-21 15:12:27 +08:00
Louis Lam
211b44269c Do not close feature-request 2022-02-21 11:48:03 +08:00
Louis Lam
7638b73645 Fix #1300 2022-02-15 23:30:07 +08:00
Mik Mueller
a997f8e4f9 Update de-DE.js 2022-02-15 12:58:02 +01:00
Mik Mueller
09dbb143ea Merge branch 'louislam:master' into master 2022-02-15 12:51:21 +01:00
Hans Mayer
f19e983818 Merge remote-tracking branch 'origin/master' into translations-de 2022-02-14 14:39:21 +01:00
Louis Lam
d0ed99a310 Merge pull request #1298 from ananthkamath/master
Fix mattermost couldn't find channel issue
2022-02-13 23:56:12 +08:00
Ananth Kamath
258d93be72 Fix mattermost couldn't find channel issue 2022-02-13 21:17:02 +05:30
Louis Lam
986ddd92ff Merge pull request #1198 from Buchtic/master
CSY translation
2022-02-13 14:11:00 +08:00
AnnAngela
c75c6c5640 Update zh-CN.js
Update DingDing and AliyunSms setting dialogs for better translations and document links
2022-02-11 22:50:46 +08:00
AnnAngela
5aed36b470 Update zh-CN
----
关于 smtpDkimKeySelector:
Google Workspace 的帮助里用词为
[前缀选择器](https://annangela.page.link/smtpDkimKeySelector)
2022-02-10 22:45:24 +08:00
sovushik
76b9fb967f Update ru-RU.js
Add new string
2022-02-09 21:37:45 +05:00
sovushik
b58120d258 Update ru-RU.js
Correct some words on Russian
2022-02-09 21:26:47 +05:00
sovushik
79f99ce215 Update ru-RU.js
Add new string
2022-02-09 21:19:00 +05:00
Louis Lam
e7e30bf497 update to 1.11.4 2022-02-09 21:54:33 +08:00
Louis Lam
efaa55ad1f Merge pull request #1269 from holao09/master
Update Vietnamese language
2022-02-09 21:42:02 +08:00
Louis Lam
32a898bee5 Merge pull request #1270 from rovast/master
Update zh-CN  translation for setting module.
2022-02-09 21:36:07 +08:00
Louis Lam
561a0a3c9a Merge pull request #1278 from jamesmacwhite/disable-auth-lang
Fix minor typos on disable auth warning
2022-02-09 21:35:37 +08:00
Việt Nguyễn
daac9ddffc Update Vietnamese language
Cập nhật một số thông tin tiếng Việt
2022-02-09 16:17:10 +07:00
James White
6bd2ee8c69 Fix minor typos on disable auth warning 2022-02-08 21:53:15 +00:00
rovast
45dca072b2 Update zh-CN translation for setting module. 2022-02-07 15:28:21 +08:00
Mik Mueller
7d8b72c6c0 Merge branch 'louislam:master' into master 2022-02-06 10:57:10 +01:00
Hans Mayer
40cc885eb8 resolve conflict after update state 2022-02-05 11:48:48 +01:00
Louis Lam
742ad083e5 Fix security vulnerabilities 2022-02-03 12:26:50 +08:00
Louis Lam
27f4f5ee0b Merge remote-tracking branch 'origin/master' 2022-02-03 12:20:29 +08:00
Louis Lam
41f1686147 Fix security vulnerabilities 2022-02-03 12:20:15 +08:00
Louis Lam
faab1ead92 Merge pull request #1251 from dave9123/patch-2
id-ID.js - Fixed the grammar issue
2022-02-03 12:11:31 +08:00
Mik Mueller
f1007ad42f Update de-DE.js 2022-02-02 22:59:13 +01:00
Mik Mueller
dd28ecaa2d Update de-DE.js 2022-02-02 22:57:02 +01:00
Mik Mueller
ffa585376d Merge branch 'louislam:master' into master 2022-02-02 22:54:23 +01:00
dave9123
c1c1e2ba5b Fixed the grammar issue
Here's my pull request
2022-02-02 10:13:55 +07:00
Louis Lam
2f7e24191a Merge pull request #1237 from dave9123/patch-1
[id-ID] Fixed some grammar error
2022-02-02 00:31:50 +08:00
vfaergestad
0fce1b4b9b Update nb-NO.js (#1232)
Improved and finished the translation.
2022-02-02 00:31:00 +08:00
Mik Mueller
11c2e86bfe Update src/languages/de-DE.js
Co-authored-by: Alf <62615304+Alf-Melmac@users.noreply.github.com>
2022-02-01 08:13:30 +01:00
Mik Mueller
1bbf17f3da Update src/languages/de-DE.js
Co-authored-by: Alf <62615304+Alf-Melmac@users.noreply.github.com>
2022-02-01 08:13:23 +01:00
Mik Mueller
39f8b30b36 Update src/languages/de-DE.js
Co-authored-by: Alf <62615304+Alf-Melmac@users.noreply.github.com>
2022-02-01 08:13:13 +01:00
Mik Mueller
ffb2c2996b Update src/languages/de-DE.js
Co-authored-by: Alf <62615304+Alf-Melmac@users.noreply.github.com>
2022-02-01 08:12:42 +01:00
dave9123
65896ed035 Fixed some grammar error
I fixed at some part of the text.
2022-01-31 08:01:45 +07:00
Mik Mueller
b13b20bd95 improve certain German words and phrases, improve grammer in README.md 2022-01-30 00:17:25 +01:00
Alvin Pergens
8febff9282 fix comments 2022-01-28 15:35:33 +01:00
Alvin Pergens
90f2497548 change data for Alerta 2022-01-28 15:14:34 +01:00
Phuong Nguyen Minh
a9df7b4a14 Update vi.js (#1226)
* update vi.js
2022-01-28 21:23:37 +08:00
Alvin Pergens
cefe43800f add alerta service 2022-01-27 20:54:04 +01:00
Computroniks
97a5b400db Added log out button to nav bar
Implements Logout button in navbar #1209

Signed-off-by: Computroniks <mnickson@sidingsmedia.com>
2022-01-27 19:45:31 +00:00
Computroniks
ca89f84b9a Added sign-out-alt icon
Signed-off-by: Computroniks <mnickson@sidingsmedia.com>
2022-01-27 18:57:14 +00:00
Computroniks
eaf370637e Fixed dark mode checkbox
The border colour of the checkbox has been changed to make it more
visible to the user when the dark mode is in use.

Signed-off-by: Computroniks <mnickson@sidingsmedia.com>
2022-01-27 17:40:03 +00:00
Arjun Komath
23796723dd Address code review
Add missing comma

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2022-01-21 20:42:08 +11:00
Arjun Komath
51b7a2badb remove log 2022-01-21 07:43:14 +00:00
Arjun Komath
74c584f544 Add Push by Techulus 2022-01-21 07:42:03 +00:00
Tarun Singh
0345719e53 added cleartimeout in case client is already ended 2022-01-20 13:20:54 -05:00
Tarun Singh
22256dfcd2 added timeout for removing the dead loop state 2022-01-20 13:04:59 -05:00
Louis Lam
c3c4db52ec Merge pull request #1184 from Khord/patch-1
Rename 2FA/TOTP field ID for password manager filling compatibility
2022-01-20 15:18:42 +08:00
Louis Lam
aba6cb2c52 Merge pull request #1169 from jbenguira/patch-1
Fixed #1024
2022-01-19 14:41:15 +08:00
Louis Lam
ff0e85737f Merge pull request #1182 from sovushik/patch-4
Update ru-RU.js
2022-01-19 14:37:08 +08:00
Buchtič
4713820da7 first csy translation 2022-01-18 14:44:11 +01:00
Buchtič
a99e87c02c cs-CZ 2022-01-18 08:50:11 +01:00
Buchtič
3f8ca82434 cs-CZ translation 2022-01-18 08:48:39 +01:00
Buchtič
60f1eb7b45 new cs-CZ.js 2022-01-17 18:42:32 +01:00
Louis
55a593f75d Merge remote-tracking branch 'origin/master' 2022-01-18 01:24:28 +08:00
Louis
a0d51a15cf Fix security vulnerabilities 2022-01-18 01:24:07 +08:00
Louis Lam
5a08b42e4f Merge pull request #1194 from Rayzggz/master
Update zh-CN.js
2022-01-18 01:17:33 +08:00
Louis
6961af005e eslint 2022-01-18 01:12:25 +08:00
Roy Feng
847a19afc1 Update zh-CN.js 2022-01-17 15:03:39 +08:00
Louis Lam
7532e7fd3e Merge pull request #1192 from drodmantras/master
Update sl-SI.js
2022-01-17 14:18:27 +08:00
Erik
63a3704836 Update sl-SI.js 2022-01-16 12:29:00 +01:00
Hans Mayer
3e87eb596f change wording, according to PR suggestions 2022-01-15 12:25:17 +01:00
Hans Mayer
c679613f7e Updates some DE translations, fix typo in resolverserverDescription, removes some duplicates in languages 2022-01-14 19:06:21 +01:00
Louis
bd8fa17887 Merge remote-tracking branch 'origin/master' 2022-01-15 01:25:50 +08:00
Louis
d1a99b0a22 Check Node.js version, better error message 2022-01-15 01:25:28 +08:00
Joseph Benguira
3b9fac2942 Update server/prometheus.js
removed useless spaces

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2022-01-14 08:51:45 +02:00
Dylan Khor
812e80030b revert Token because of language file 2022-01-13 23:43:57 -05:00
Dylan Khor
b89efa49aa retain Token verbiage in display name
since "Token" is used in several places in the 2FA setup screen
2022-01-13 16:58:46 -05:00
Dylan Khor
6490ef3787 rename 2fa input element id and display name 2022-01-13 16:46:09 -05:00
sovushik
329c8cbc2d Update ru-RU.js
Add new string
2022-01-13 22:07:21 +05:00
Louis Lam
2bf9764cec Merge pull request #1175 from sovushik/patch-3
Update ru-RU.js
2022-01-13 13:18:23 +08:00
Louis Lam
c116754360 Merge pull request #1171 from Saibamen/patch-1
Update pl.js
2022-01-13 13:17:06 +08:00
Louis Lam
227bbdea2f [MQTT] Try to improve error handling 2022-01-13 12:42:34 +08:00
Louis Lam
6272514820 [MQTT] Use existing fields instead of creating new ones (Server) 2022-01-13 11:53:08 +08:00
Louis Lam
1c8407a433 [MQTT] Use existing fields instead of creating new ones (UI) 2022-01-13 11:36:55 +08:00
Louis Lam
32ec4beda0 Merge branch 'master' into mqtt 2022-01-13 11:24:45 +08:00
Louis Lam
2c7a701c84 Merge remote-tracking branch 'origin/master' 2022-01-13 11:24:21 +08:00
Louis Lam
9462646ad3 Fix vulnerabilities 2022-01-13 11:22:58 +08:00
Louis Lam
482b3f9233 Update server/util-server.js
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2022-01-13 11:20:32 +08:00
Louis Lam
6014ed1156 Fix conflict 2022-01-13 11:19:26 +08:00
Louis Lam
bfee63452d Merge branch 'master' into mqtt 2022-01-13 11:16:58 +08:00
Louis Lam
fd1fce0143 Update stylelint from 13.13.x to 14.2.x 2022-01-13 11:15:38 +08:00
Louis Lam
076d6bdbb6 Merge branch 'master' into mqtt
# Conflicts:
#	package-lock.json
#	server/database.js
2022-01-13 11:09:16 +08:00
sovushik
52e0d74a1e Update ru-RU.js
Add new string
2022-01-12 20:49:41 +05:00
Adam Stachowicz
23532aaafe Update pl.js
Addendum to ab61acab63
2022-01-12 12:26:23 +01:00
Louis Lam
ab61acab63 Merge pull request #1170 from NixNotCastey/update-pl
Update pl.js
2022-01-12 17:39:12 +08:00
Łukasz Szczepański
06aab3dee8 Added missing text and fix typos 2022-01-12 09:48:37 +01:00
Joseph Benguira
13acdd4c65 Fix for issue in logs
This fix address the issue described here: https://github.com/louislam/uptime-kuma/issues/1024
2022-01-12 10:12:12 +02:00
Louis Lam
fe0bce268d Merge pull request #1164 from ledeuns/master
Fix comment (FreeBSD->*BSD)
2022-01-12 01:49:57 +08:00
Louis
ed64853125 Keep FBSD, BSD for ping only 2022-01-12 01:44:01 +08:00
Denis
0f822d3b2a FBSD does not exists anymore 2022-01-11 13:42:51 +01:00
Denis
6bda5c6329 update comment 2022-01-11 13:39:45 +01:00
Denis Fondras
44bc98a453 Merge branch 'louislam:master' into master 2022-01-11 13:37:54 +01:00
Louis
f9751d0c01 Fix FBSD to BSD https://github.com/louislam/uptime-kuma/pull/1155#issuecomment-1009544236 2022-01-11 19:15:28 +08:00
Denis
53df9a36e3 reintroduce exports.FBSD 2022-01-11 10:07:00 +01:00
Louis Lam
ccfd04a431 Merge pull request #1155 from ledeuns/master
ping path is common to all BSDs
2022-01-10 18:20:06 +08:00
Louis Lam
9324137123 Merge pull request #1151 from sovushik/patch-2
Update ru-RU.js
2022-01-10 18:19:04 +08:00
Louis Lam
9f063cf477 Merge branch 'master' into patch-2 2022-01-10 17:56:47 +08:00
Louis Lam
b83c896d0c Merge pull request #1150 from sovushik/patch-1
Update ru-RU.js
2022-01-10 17:55:46 +08:00
Louis Lam
aa37383065 Merge pull request #1154 from jamesmacwhite/pull-request-guidelines
Update PULL_REQUEST_TEMPLATE.md
2022-01-10 17:54:55 +08:00
Louis Lam
5e2c39eb4b Merge pull request #1144 from alex3025/master
Fixed italian (it-IT) translations
2022-01-10 17:54:22 +08:00
Louis Lam
2a1f011f05 Merge pull request #1153 from drodmantras/master
Update sl-SI.js
2022-01-10 17:53:03 +08:00
Zack Elia
ea43422ccf Implement gorush notifications 2022-01-09 12:05:11 -05:00
Denis
8063449f49 ping path is common to all BSDs 2022-01-09 17:27:24 +01:00
James White
b6ad4c845a Update PULL_REQUEST_TEMPLATE.md
Correct checklist item and make the UI type of change consistent with all others.
2022-01-09 15:31:26 +00:00
Erik
cdcdf377ec Update sl-SI.js
Small langue updates
2022-01-09 11:39:05 +01:00
sovushik
30a345d8b6 Update ru-RU.js
Updated language files and added new lines
2022-01-08 23:00:18 +05:00
sovushik
83d60fea29 Update ru-RU.js
1. Updated the language lines (in the correct declension)
2. Added new lines for the "Create Incident" functionality
2022-01-08 22:46:05 +05:00
Marc Harnos
0bbe157099 change parsing priority for all passed arguments
update all passed args in server.js to prioritize command line, then use
env.UPTIME_KUMA_ environment variables, then use the generic environment
variable versions env.HOST, env.PORT, env.SSL_KEY, env.SSL_CERT and fall
back to default values where applicable
2022-01-08 18:32:42 +01:00
Marc Harnos
0053a29d10 add validation to port value parsing
only port configurations that are valid (not isNaN) after parseInt
are considered to be used in port variable
2022-01-08 18:27:39 +01:00
Marc Harnos
2c8d5d28e9 simplify host fallback logic
move decision logic for freeBSD HOST environment var into temp var
2022-01-08 18:25:12 +01:00
Matteo D
2304c53c8d Fixed some translations
And made them more user-friendly.
2022-01-08 13:28:48 +01:00
Nelson Chan
1bbd744d02 Chore: Improve syntax 2022-01-07 14:29:42 +08:00
Nelson Chan
2e0e35a1ee Fix: Fix typo 2022-01-07 12:34:01 +08:00
Nelson Chan
1e92487f30 Chore: Remove onDelete as unused 2022-01-07 12:28:08 +08:00
Nelson Chan
edd2534a1b Fix: Clear metrics also on stop and edit 2022-01-07 12:26:26 +08:00
Nelson Chan
f6ef390c76 Fix: Remove Prom. metrics on delete monitor 2022-01-07 12:04:57 +08:00
Louis Lam
d4b86dc472 Merge pull request #1133 from thomasleveil/patch-1
fix `TypeError: Cannot read property 'id' of null`
2022-01-06 16:19:36 +08:00
Thomas LÉVEIL
46fa6a56fa fix TypeError: Cannot read property 'id' of null
when testing a Google Chat notification

see https://github.com/louislam/uptime-kuma/issues/1126#issuecomment-1006343423
2022-01-06 08:48:12 +01:00
Louis Lam
ec5037f30d update to 1.11.3 2022-01-06 14:51:20 +08:00
Louis Lam
81a194d826 Merge remote-tracking branch 'origin/master' 2022-01-06 14:47:21 +08:00
Louis Lam
64b3e04d3f Fix #1129 2022-01-06 14:34:45 +08:00
Louis Lam
4ee829ab25 Merge pull request #1130 from bilipp/google-chat-notifications
Fix Google Chat notification type mismatch
2022-01-06 13:05:55 +08:00
Philipp Bischoff
bcc3cec7d6 extract translation for notification type 2022-01-05 23:57:40 +01:00
Philipp Bischoff
f8c5015e3f fix google chat type mismatch 2022-01-05 23:44:14 +01:00
Louis Lam
8f3ec33591 update to 1.11.2 2022-01-05 16:40:50 +08:00
Louis Lam
c5fe3a64c2 Merge remote-tracking branch 'origin/master' 2022-01-05 16:26:03 +08:00
Louis Lam
2a1456cfd0 Merge pull request #1124 from MrEddX/bulgarian
Update bg-BG.js
2022-01-05 14:28:39 +08:00
MrEddX
69dfc0c0d2 Update bg-BG.js
Fixed some typos.
2022-01-05 08:15:34 +02:00
Louis Lam
6d11289257 Merge pull request #1095 from LeslieLeung/add-wecom-notification
feat(*): support WeCom notification
2022-01-04 22:50:30 +08:00
Leslie Leung
590859a95b Merge branch 'master' into add-wecom-notification 2022-01-03 21:43:56 +08:00
Louis Lam
f9c0ff1841 Merge pull request #1109 from iomataani/master
Updated translation
2022-01-03 20:05:46 +08:00
Louis Lam
a8566acbaa Merge pull request #1116 from Minvinea/master
Update translation FR
2022-01-03 20:04:33 +08:00
Minvinea
4b07ec23fe Update 2022-01-03 00:27:51 +01:00
Ioma Taani
0e50b71290 Merge branch 'louislam:master' into master 2021-12-31 09:09:53 +01:00
Louis Lam
390b50353f Merge pull request #1106 from MrEddX/bulgarian
Update bg-BG.js
2021-12-30 19:10:42 +08:00
MrEddX
d7cb4fa331 Update bg-BG.js
- Updated Bulgarian language file
2021-12-30 08:12:25 +02:00
Louis Lam
e18d4b6ad0 Merge pull request #1045 from bilipp/google-chat-notifications
Add support for Google Chat Notifications
2021-12-30 00:16:34 +08:00
Louis Lam
f6fc3737fc Change name from "Google Chat" to Google Chat (Google Workspace only) 2021-12-30 00:10:54 +08:00
Louis Lam
4005856ba6 run build dist when building docker image 2021-12-27 19:09:51 +08:00
Louis Lam
72a59ce7a4 add status page table 2021-12-27 18:54:48 +08:00
LeslieLeung
40b70277c7 feat(*): support WeCom notification 2021-12-26 13:11:42 +08:00
Patrick Hafner
3d6c52fbea Merge branch 'master' into customstatuspage 2021-12-25 04:12:05 +01:00
Patrick Hafner
9ee591417d Footer HTML support, updated german translation 2021-12-25 04:09:41 +01:00
Ioma Taani
a2bc74c4fd updated 2021-12-24 12:02:50 +01:00
Tarun Singh
4118de6d53 fix protocol not defined bug 2021-12-23 19:39:47 -05:00
Louis Lam
a48176bd48 Merge pull request #1080 from chakflying/feat/smtp-dkim
Feat: Add SMTP DKIM settings
2021-12-22 20:08:29 +08:00
Louis Lam
7cfc5c64b7 Missing a full stop 2021-12-22 13:49:57 +08:00
Patrick Hafner
3a12e209da Edit: editMode check before toggle 2021-12-21 03:55:25 +01:00
Patrick Hafner
2c2a824f97 Add: en & de-DE language 2021-12-21 03:31:09 +01:00
Patrick Hafner
931ca6a3ef Add: customize status page (css and poweredby) 2021-12-21 03:27:05 +01:00
Nelson Chan
624cd862a5 Feat: Expose SMTP DKIM settings 2021-12-19 13:30:53 +08:00
Tarun Singh
d3c90df8a8 fixed edit monitor fields empty issues 2021-12-18 16:35:18 -05:00
Louis Lam
0ca68f791f Merge pull request #1060 from drodmantras/master
Added sl-SI language
2021-12-18 00:58:56 +08:00
Louis Lam
6127eab517 Merge pull request #1071 from MrEddX/bulgarian
Update bg-BG.js
2021-12-18 00:57:31 +08:00
MrEddX
0de7fb69f6 Update bg-BG.js
Added new fields.
Translated new fields.
2021-12-17 12:29:53 +02:00
Louis Lam
a42932a43e Simulate Chrome's request Accept header. Better handling of #1067 2021-12-16 15:09:10 +08:00
Philipp Bischoff
a6072a0e30 google chat: only show offline message in notification when service went down 2021-12-15 13:40:21 +01:00
Ivan Bratović
475a466c7e Add attribute to basicauth-pass to prevent browsers from autocompleting (#1063) 2021-12-15 18:18:30 +08:00
Louis Lam
5bc68d7f3b Update README.md 2021-12-15 02:50:45 +08:00
Louis Lam
000703837b Update README.md 2021-12-15 02:46:13 +08:00
Erik
b10cecb362 Added sl-SI language
Added sl-SI language
2021-12-14 17:59:26 +01:00
Louis Lam
6d6cb2ad49 Merge pull request #1047 from dhfhfk/master
Update Ko-KR.js
2021-12-14 17:28:38 +08:00
Louis Lam
cb76801b85 Merge pull request #1049 from Ponkhy/german-language
Updated de-De.js
2021-12-14 13:17:22 +08:00
Ponkhy
aa92727a61 Updated de-De 2021-12-12 21:52:51 +01:00
dhfhfk
56dfa05642 Update Ko-KR.js 2021-12-12 18:56:10 +09:00
Philipp Bischoff
8ad6bd31d4 Revert "order notification types by name"
This reverts commit 8398466860.
2021-12-12 00:08:33 +01:00
Philipp Bischoff
a71569379e add missing import 2021-12-12 00:01:12 +01:00
Philipp Bischoff
8398466860 order notification types by name 2021-12-11 23:50:03 +01:00
Philipp Bischoff
8050cb8e99 implement google chat notification type 2021-12-11 23:43:12 +01:00
Louis Lam
71492aeb3a Merge remote-tracking branch 'origin/master' 2021-12-11 20:59:45 +08:00
Louis Lam
5ee5ea909d Add Github Action: close-incorrect-issue.yml 2021-12-11 20:59:31 +08:00
Louis Lam
a09b97f778 Merge pull request #1032 from titiscan/patch-1
Update fr-FR.js
2021-12-11 17:31:13 +08:00
Louis Lam
e0a08e6b5d Merge pull request #1038 from iomataani/master
Updated italian translation
2021-12-11 17:30:44 +08:00
Louis Lam
6f5cbbdf69 Merge pull request #1018 from Lrss/master
Update Danish translation
2021-12-11 17:29:46 +08:00
Louis Lam
34ee342d3e eslint 2021-12-11 17:20:51 +08:00
Andreas Brett
38f8a8ac2f Merge branch 'louislam:master' into logging 2021-12-10 17:21:55 +01:00
Ioma Taani
f793aa5264 better translations 2021-12-10 09:26:55 +01:00
Ioma Taani
728485d686 updated translations 2021-12-10 09:08:01 +01:00
titiscan
cb3429d3c7 Update fr-FR.js
typo fix
2021-12-09 17:26:05 +01:00
Louis Lam
807519d07d Merge branch 'master' into restructure-status-page 2021-12-09 21:46:35 +08:00
Louis Lam
0d69b4426e Merge pull request #1017 from SiderealArt/patch-1
update zh-TW translation
2021-12-09 21:32:10 +08:00
Louis Lam
8bb8b0a53c update to 1.11.1 2021-12-09 01:23:49 +08:00
Louis Lam
a4841eb8aa Fix #1016, .at() is not support in Safari 2021-12-09 01:19:09 +08:00
Lars Sørensen
2ef2a42e87 Fixed string enclosure as suggested by update-language-files 2021-12-08 11:35:55 +01:00
Lars Sørensen
9473cd6919 Update da-DK.js translation 2021-12-08 11:14:10 +01:00
SiderealArt
74f18a2b3f update zh-TW translation 2021-12-08 17:23:13 +08:00
Louis Lam
f9cd0eb084 fix upload-artifacts 2021-12-08 15:35:44 +08:00
Louis Lam
6a845bd937 Merge remote-tracking branch 'origin/master' 2021-12-08 15:26:19 +08:00
Louis Lam
c91f517121 Update README.md 2021-12-08 15:25:43 +08:00
Louis Lam
7899707582 update to 1.11.0 2021-12-08 15:17:37 +08:00
Louis Lam
12215af2f4 Merge pull request #1014 from iooner/patch-2
Fix typos
2021-12-08 15:04:33 +08:00
Louis Lam
d4bfe57b79 minor: improve formatting 2021-12-08 15:04:18 +08:00
Louis Lam
dcc91d6c72 Fix #922 2021-12-08 14:59:59 +08:00
Andreas Brett
e684712a77 Merge branch 'louislam:master' into logging 2021-12-07 18:21:56 +01:00
iooner
a041a7964a Fix typos 2021-12-07 14:23:13 +01:00
Louis Lam
76611ecaca Merge pull request #1011 from iomataani/master
Updated translation
2021-12-07 19:26:22 +08:00
Tarun Singh
5afc6a41e3 removed https requirement for url 2021-12-06 11:28:23 -05:00
Ioma Taani
f802154456 updated 2021-12-06 11:33:39 +01:00
Ioma Taani
9fb461976d Merge branch 'louislam:master' into master 2021-12-06 11:32:24 +01:00
Louis Lam
c8e364911f Delete close-issue.yml, no idea why not working 2021-12-06 17:46:46 +08:00
Louis Lam
88bc08e7b7 Update close-issue.yml 2021-12-06 17:36:18 +08:00
Louis Lam
03aeab0421 close issues that don't follow the issue template
Copy from axios
2021-12-06 17:31:25 +08:00
Louis Lam
f331f1a63e Merge pull request #873 from Saibamen/fix_871
Fix Telegram Bot Token displayed in notification setup view
2021-12-05 18:04:54 +08:00
Louis
d645e29455 mask telegram api url with asterisk 2021-12-05 17:40:13 +08:00
Louis Lam
b4507f9706 Merge pull request #992 from jlbrt/stackfield-notifications
Add support for Stackfield notifications
2021-12-05 16:45:30 +08:00
Louis Lam
fc6d0d1fca Merge pull request #1000 from BCsabaEngine/master
NPM update and (boring) HU lang
2021-12-05 16:30:31 +08:00
Louis
b62f1475ee 🐍 2021-12-05 16:28:59 +08:00
Louis
d47d8517a8 update apprise to 0.9.6 2021-12-05 16:05:52 +08:00
Ioma Taani
19d2db6c8c better translation 2021-12-04 11:19:56 +01:00
Andreas Brett
dcc7856b5d Merge branch 'louislam:master' into logging 2021-12-04 09:59:10 +01:00
Balázs Csaba
5a8162747c Upgrade qrcode to 1.5.0 2021-12-03 22:47:40 +01:00
Balázs Csaba
220108ebc6 Upgrade bree to 7.1 2021-12-03 22:39:38 +01:00
Balázs Csaba
984a3704e0 HU lang 2021-12-03 22:29:53 +01:00
Ioma Taani
909412c87e Merge branch 'louislam:master' into master 2021-12-03 11:11:38 +01:00
Ashish Bansal
481fd3a05f Updated monitor service details in README.md (#990)
* Updated monitor service details in README.md

Added `Steam Gamer Server' to the monitor service list.

* Update README.md

* Update README.md

* Update README.md
2021-12-03 15:49:46 +08:00
Louis Lam
5434e2da4f Merge pull request #993 from Saibamen/patch-1
Fix typos in markdown files
2021-12-03 15:48:57 +08:00
Ioma Taani
b3d348dcea Translation Update (#994)
* Better translation

* better translation

* aggiornato
2021-12-03 15:48:11 +08:00
Csaba Balázs
0aca0455ab HU language typo and missing items (#996)
* HU language

* run eslint on hu.js

* Last HU typo

* package.json valid required node engine syntax

Package.json required node engine version can contain multiple rules separated with ||. With this mode package-lock.json will be valid and error codes does not diplay.

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2021-12-03 15:47:35 +08:00
Louis Lam
8f3ef734bc disable e2e test, as it is getting unstable recently on GitHub action 2021-12-03 01:31:19 +08:00
Ioma Taani
120eb0d85f aggiornato 2021-12-02 12:51:10 +01:00
Ioma Taani
4aaed0837e Merge branch 'louislam:master' into master 2021-12-02 12:44:13 +01:00
Adam Stachowicz
60657132c0 Update PULL_REQUEST_TEMPLATE.md 2021-12-02 11:19:59 +01:00
Adam Stachowicz
76cbef85d5 Update README.md 2021-12-02 11:18:30 +01:00
Adam Stachowicz
e17ef02008 Update CONTRIBUTING.md 2021-12-02 11:15:14 +01:00
Adam Stachowicz
f33d55c92d Update README.md 2021-12-02 11:09:27 +01:00
Jonas Liebert
67849a9e84 add support for stackfield notifications 2021-12-02 08:53:45 +01:00
Louis Lam
ee79a34148 Merge pull request #989 from BCsabaEngine/master
HU language typo
2021-12-02 12:44:18 +08:00
Louis Lam
d2f0480889 Merge pull request #988 from tgcentral/readme-md-typo
Typo correction
2021-12-02 12:43:19 +08:00
Balázs Csaba
c36190bba6 Node engine version 2021-12-01 15:40:22 +01:00
Balázs Csaba
4b3fae53d4 HU language typo 2021-12-01 15:32:39 +01:00
tgcentral
4dd60cba3d Typo correction 2021-12-01 09:43:58 +00:00
Ioma Taani
4bc84d2122 Merge branch 'louislam:master' into master 2021-12-01 08:47:57 +01:00
Louis Lam
a796f80018 Merge pull request #902 from ivanbratovic/improve-translatables
Fix untranslatable parts of the UI
2021-12-01 13:59:00 +08:00
Andreas Brett
c9b0a81cdc Update MonitorHistory.vue 2021-11-29 20:39:57 +01:00
Andreas Brett
2f97f44086 Update MonitorHistory.vue 2021-11-29 20:37:44 +01:00
Andreas Brett
a13bdaac84 Merge branch 'master' into logging 2021-11-29 20:32:42 +01:00
Louis Lam
40cb22e671 Merge pull request #963 from kffl/feat/serwersms-provider
Add SerwerSMS.pl notification provider
2021-11-29 20:43:38 +08:00
Ivan Bratović
d95258e7db Merge remote-tracking branch 'upstream/master' into improve-translatables 2021-11-29 12:51:08 +01:00
Ivan Bratović
baae4b5a5e Remove unused translation keys from hr-HR 2021-11-29 12:49:38 +01:00
Ivan Bratović
c1b118a0f6 Use existing Example translation for HTTP headers and body placeholders 2021-11-29 12:49:08 +01:00
Ivan Bratović
9c5466890e Revert "Replace body and header placeholder functions with translations"
This reverts commit 2c85491ee0.
2021-11-29 12:40:53 +01:00
Louis Lam
bf8dbd78b3 temporary disable test for settings page 2021-11-29 17:25:30 +08:00
Louis Lam
6cd130de38 minor 2021-11-29 17:20:12 +08:00
Louis Lam
a864b72e03 fix pushover for general message 2021-11-29 17:19:55 +08:00
Louis Lam
5070927478 Merge pull request #980 from MrEddX/bulgarian
Update bg-BG.js
2021-11-29 16:56:02 +08:00
Louis Lam
bedc1f8617 Merge pull request #966 from louislam/lazy-load-lang
Lazy load language files
2021-11-29 16:54:25 +08:00
Louis Lam
077f3837d9 update language guide 2021-11-29 16:53:00 +08:00
Louis Lam
aea128a85b make settings' menu reactive 2021-11-29 16:50:00 +08:00
Louis Lam
c50b2b636a [lazy load lang] load the language file on create 2021-11-29 16:45:52 +08:00
MrEddX
a284703d9e Update bg-BG.js
- Fixed existing field
- Added new field
- Translated new field
2021-11-28 07:11:20 +02:00
kffl
64ec766423 translate(serwersms): fix pl translation capitalization
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-27 13:22:54 +01:00
kffl
186c11540f style(serwersms): add missing trailing commas
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-27 13:16:17 +01:00
Ioma Taani
4d947d9374 better translation 2021-11-26 10:37:42 +01:00
Ioma Taani
4888c97d86 Better translation 2021-11-26 10:33:15 +01:00
Louis Lam
50593f3edf [wip] lazy load language file 2021-11-26 16:31:19 +08:00
Paweł Kuffel
c1267e9b3b feat: add SerwerSMS notification provider 2021-11-25 18:24:36 +01:00
Ivan Bratović
2ca7a5b962 Merge branch 'master' into improve-translatables 2021-11-24 10:03:30 +01:00
Louis Lam
9f0c66d775 fix node-sqlite3 security issues 2021-11-24 14:53:15 +08:00
Louis Lam
a1f9a82537 Merge pull request #884 from thomasleveil/ux/add-group-at-the-top
🚸 Status page - add group action adds the new group at the top
2021-11-24 11:48:58 +08:00
Louis Lam
37e6ca8d77 Merge pull request #950 from dingdayu/master
Update dingding notification title
2021-11-24 11:36:00 +08:00
Fluency
e3745da986 Merge branch 'master' into master 2021-11-23 10:26:45 -08:00
Louis Lam
0b0fd6609d Merge pull request #951 from iomataani/master
Updated translations.
2021-11-24 00:37:12 +08:00
Ioma Taani
3a32fd6f42 aggiornata la traduzione 2021-11-23 16:39:38 +01:00
Ioma Taani
97cb060cf5 another typo 2021-11-23 16:39:04 +01:00
Ioma Taani
5afb29f8f9 typo 2021-11-23 16:35:18 +01:00
Ioma Taani
f9b8dbf4db Merge branch 'louislam:master' into master 2021-11-23 16:30:48 +01:00
Louis Lam
92a5f18bf5 Merge pull request #864 from ivanbratovic/http-basicauth
Implement explicit HTTP "basic" authentication support
2021-11-23 22:48:54 +08:00
小雨
dce908a07b Update dingding notification title
Add the status to the title, you can see the message title on the friend list page.
2021-11-23 20:36:22 +08:00
Louis
4155f84eec improve basic auth style 2021-11-23 19:20:55 +08:00
Louis Lam
94ffeeeab6 update dependencies 2021-11-23 13:32:24 +08:00
Louis Lam
3d222ac5f5 fix btoa is not define 2021-11-23 12:59:48 +08:00
Louis Lam
c811c1ccde Merge pull request #753 from chakflying/settings-redesign
UI: Redesign/organize settings page
2021-11-23 12:46:59 +08:00
Ioma Taani
bd3d34400d Merge branch 'master' of https://github.com/iomataani/uptime-kuma 2021-11-22 23:39:10 +01:00
Tarun Singh
35da8c78f4 added connection timeout and refactored code 2021-11-22 03:21:53 -05:00
Fluency
7179c6cc4c Fix punctuation in extra/update-version.js
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-19 10:30:31 -08:00
Andreas Brett
ed96757b24 Merge branch 'louislam:master' into logging 2021-11-19 08:56:25 +01:00
Tarun Singh
3306f4a8e0 removed extra logging 2021-11-18 14:03:23 -05:00
Louis Lam
5d3bf68123 add remove-2fa command 2021-11-18 18:22:03 +08:00
Fluency
a2de9e4e36 Fixed export-function signature being scrambled. 2021-11-17 16:02:31 -08:00
Nelson Chan
1f77526210 Chore: Run spell check 2021-11-17 14:09:12 +08:00
Nelson Chan
88ed965d69 Test: Disable clear stats test 2021-11-17 10:52:14 +08:00
Nelson Chan
7f4d5a0f76 Test: fix tests
Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Attempt to fix tests

Test: Investigate error message

Test: Attempt to fix tests

Chore: Cleanup code

Test: Attempt to fix tests

Test: Attempt to fix tests
2021-11-17 10:45:24 +08:00
Nelson Chan
df813fbdee Fix: Add save in monitor history 2021-11-17 10:45:19 +08:00
Nelson Chan
07742799ed Test: Fix tests
Test: Add clear stats test

Test: Attempt to fix tests

Test: Add test for disable auth

Update README
2021-11-17 10:45:19 +08:00
Nelson Chan
f65cc655c0 Fix: Fix nav highlight in settings sub-page 2021-11-17 10:45:19 +08:00
Nelson Chan
1a218aaa17 Fix: Fix page transition & improve active handling
Fix: Fix current route parsing
2021-11-17 10:45:19 +08:00
Nelson Chan
369cad90c1 WIP: Convert to use vue-router & improve layout
WIP: Fix security page & improve layout

WIP: Fix displaying current page

UI: Improve spacing

Chore: Improve styling
2021-11-17 10:45:18 +08:00
Nelson Chan
f9bb48de13 WIP: Convert Settings to components 2021-11-17 10:45:18 +08:00
Tarun Singh
3f5133d1ba Added authentication logic 2021-11-16 20:44:10 -05:00
Louis Lam
74d2b38cb6 Merge pull request #925 from iomataani/italian-language-update
Translation update
2021-11-16 19:12:07 +08:00
Louis Lam
7bba4fe2d0 Merge pull request #926 from MG8853/patch-1
Update ja.js
2021-11-16 18:53:30 +08:00
MultiGamer8853
be3a791e6e Update ja.js
日本語を最適化
2021-11-16 18:14:23 +09:00
Ioma Taani
9747048890 correzioni e miglioramenti 2021-11-16 09:04:10 +01:00
Andreas Brett
6f2dcc6dd7 using provided tsc config 2021-11-15 18:07:18 +01:00
Andreas Brett
57bed4d672 Merge branch 'louislam:master' into logging 2021-11-15 18:04:45 +01:00
Andreas Brett
df36a4bb3c console.info for level "info" 2021-11-15 18:02:14 +01:00
Andreas Brett
e5913c5abc separate log functions 2021-11-15 17:52:28 +01:00
Phuong Nguyen Minh
d5d957b748 update vi.js (#853)
* update vi.js

* Update vi.js

* Update vi.js
2021-11-15 13:27:31 +08:00
Ioma Taani
5cdb5edeb3 corretto 2021-11-13 17:00:23 +01:00
Ioma Taani
73c18b6ff0 correzione 2021-11-13 16:53:07 +01:00
Ivan
567ea346fe Add missing translations for placeholders in EditMonitor page 2021-11-12 15:30:31 +01:00
Ivan
453f6fbadf Add more missing translations 2021-11-12 15:19:33 +01:00
Ivan
dd79042128 Add translation for "Info" in Settings 2021-11-12 15:14:28 +01:00
Ivan
583e6bf978 Update croatian language for testing new translation 2021-11-12 13:32:24 +01:00
Ivan
b1fca7c1a7 Add translation of toast success message 2021-11-12 12:00:10 +01:00
Ivan
19dd11d624 Add translation for incident error message 2021-11-12 10:14:23 +01:00
Ivan
42ce34b6c7 Add more Status page tranlations 2021-11-12 09:54:31 +01:00
Ivan
b7a9d1474f Fix translation of selected incident style 2021-11-12 09:53:41 +01:00
Ivan
31fa67452e Delint English language file 2021-11-12 09:31:27 +01:00
Ivan
9ef3727c91 Backed out of commit be1933614
Running update-language-files will just confuse translators
2021-11-12 09:29:06 +01:00
Ivan Bratović
ed39485af9 Merge with upstream master
Signed-off-by: Ivan Bratović <ivanbratovic4@gmail.com>
2021-11-12 09:23:20 +01:00
Ioma Taani
daef238a70 Updated Italian Language (#911)
Co-authored-by: Paride Barison <paride.barison@lantechlongwave.it>
2021-11-12 01:28:22 +08:00
Andreas Brett
d21f7971b5 missed settings 2021-11-11 12:56:53 +01:00
Andreas Brett
bdcdf47e52 introduce consistent logging 2021-11-11 12:31:28 +01:00
Ivan
4cc433166e Add missing translation for SMTP security option 2021-11-11 11:14:21 +01:00
Ivan
28f530394e Add missing translation lookup for ClickSendSMS 2021-11-11 11:12:48 +01:00
Ivan
b0615d347b Add incident creation translations 2021-11-11 11:07:48 +01:00
Ivan
be19336149 Run update-language-files for all languages 2021-11-11 10:57:33 +01:00
Ivan
94508cae2f Add some missing translations 2021-11-11 10:54:36 +01:00
Ivan
265cca9ed1 Replace "Default" notification badge with translation 2021-11-11 10:54:09 +01:00
Ivan
267654c987 Replace hard-coded names for groups in Status page with translations 2021-11-11 10:53:38 +01:00
Ivan
2c85491ee0 Replace body and header placeholder functions with translations 2021-11-11 10:52:22 +01:00
Ivan Bratović
5d836cf05d [empty commit] pull request for updating translatables 2021-11-10 10:09:21 +01:00
Adam Stachowicz
ba46fb6b1c Clickable URL 2021-11-10 09:11:19 +01:00
Calum Bird
f55350bebc Generated documentation :) 2021-11-09 21:24:31 -08:00
Tarun Singh
3721d11259 changed table column names for more specifity 2021-11-09 18:53:00 -05:00
Louis Lam
5df34cd137 Merge pull request #885 from ZegertBoele/patch-1
Update to dutch translations
2021-11-09 23:20:21 +08:00
Louis Lam
bf64095cea update to 1.10.2 2021-11-09 22:42:13 +08:00
Louis Lam
2333d1c7a7 Merge remote-tracking branch 'origin/master' 2021-11-09 22:37:20 +08:00
Louis Lam
95bae8289d Fix setting page when disabled auth 2021-11-09 22:37:05 +08:00
Louis Lam
45f7c647a6 Update feature_request.yaml 2021-11-09 21:31:04 +08:00
Zegert Boele
dff1056bb1 Update nl-NL.js
@deefdragon noticed a flaw, fixed in here
2021-11-09 09:52:09 +01:00
Zegert Boele
62222c0336 Update src/languages/nl-NL.js
@koen20 added this correction.

Co-authored-by: Koen Habets <6172623+koen20@users.noreply.github.com>
2021-11-09 09:49:42 +01:00
Ivan Bratović
34d8984e3a Merge branch 'master' into http-basicauth 2021-11-07 17:15:36 +01:00
Zegert Boele
222540898b Some translations were not translated
Some translations were not translated yet. I have added them and can be contacted if you want more English-Dutch translations.
2021-11-05 13:57:55 +01:00
Thomas LEVEIL
baf3612ece 🚸 Status page - add group action adds the new group at the top of the page 2021-11-05 11:27:19 +01:00
Tarun Singh
149015556b server url changes 2021-11-04 22:25:29 -04:00
Tarun Singh
2bcbeba384 update review suggestions
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-04 22:23:02 -04:00
Tarun Singh
d5d07da4ee update review suggestions
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-04 22:22:53 -04:00
Tarun Singh
2d802585ff Update review suggestions
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2021-11-04 22:21:54 -04:00
Ivan Bratović
0481a241f3 Add translated placeholders for editing basic auth 2021-11-04 10:22:42 +01:00
Ivan Bratović
179ca232bc Minor refactor - change variable names and add commas to object definitions 2021-11-04 10:14:17 +01:00
Ivan Bratović
0dcb7aed21 Delinting 2021-11-04 09:50:10 +01:00
Ivan Bratović
23736549f9 Implement HTTP basic auth feature 2021-11-04 09:50:10 +01:00
Ivan Bratović
665c263c03 Add db migrations for new basic auth fields 2021-11-04 09:50:10 +01:00
Tarun Singh
6828e8ef6d Merge branch 'master' of https://github.com/tarun7singh/uptime-kuma 2021-11-03 21:47:44 -04:00
Tarun Singh
670754b697 added MQTT monitor type 2021-11-03 21:46:43 -04:00
Adam Stachowicz
314fa18bdc Fix #871 2021-11-04 00:19:04 +01:00
Louis Lam
6d1baa329a draft for restructure status page 2021-11-02 12:26:22 +08:00
Willian Rodrigues Barbosa
036218f711 Add badges to favicon 2021-10-29 22:25:32 -03:00
211 changed files with 19716 additions and 8736 deletions

View File

@@ -28,6 +28,8 @@ SECURITY.md
tsconfig.json
.env
/tmp
/babel.config.js
/ecosystem.config.js
### .gitignore content (commented rules are duplicated)
@@ -42,4 +44,6 @@ dist-ssr
#!/data/.gitkeep
#.vscode
### End of .gitignore content

View File

@@ -1,4 +1,9 @@
module.exports = {
ignorePatterns: [
"test/*",
"server/modules/apicache/*",
"src/util.js"
],
root: true,
env: {
browser: true,
@@ -17,39 +22,47 @@ module.exports = {
requireConfigFile: false,
},
rules: {
"linebreak-style": ["error", "unix"],
"camelcase": ["warn", {
"yoda": "error",
eqeqeq: [ "warn", "smart" ],
"linebreak-style": [ "error", "unix" ],
"camelcase": [ "warn", {
"properties": "never",
"ignoreImports": true
}],
// override/add rules settings here, such as:
// 'vue/no-unused-vars': 'error'
"no-unused-vars": "warn",
"no-unused-vars": [ "warn", {
"args": "none"
}],
indent: [
"error",
4,
{
ignoredNodes: ["TemplateLiteral"],
ignoredNodes: [ "TemplateLiteral" ],
SwitchCase: 1,
},
],
quotes: ["warn", "double"],
semi: "warn",
"vue/html-indent": ["warn", 4], // default: 2
quotes: [ "warn", "double" ],
semi: "error",
"vue/html-indent": [ "warn", 4 ], // default: 2
"vue/max-attributes-per-line": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/html-self-closing": "off",
"vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
"no-multi-spaces": ["error", {
"no-multi-spaces": [ "error", {
ignoreEOLComments: true,
}],
"space-before-function-paren": ["error", {
"array-bracket-spacing": [ "warn", "always", {
"singleValue": true,
"objectsInArrays": false,
"arraysInArrays": false
}],
"space-before-function-paren": [ "error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
"curly": "error",
"object-curly-spacing": ["error", "always"],
"object-curly-spacing": [ "error", "always" ],
"object-curly-newline": "off",
"object-property-newline": "error",
"comma-spacing": "error",
@@ -60,36 +73,36 @@ module.exports = {
"space-infix-ops": "warn",
"arrow-spacing": "warn",
"no-trailing-spaces": "warn",
"no-constant-condition": ["error", {
"no-constant-condition": [ "error", {
"checkLoops": false,
}],
"space-before-blocks": "warn",
//'no-console': 'warn',
"no-extra-boolean-cast": "off",
"no-multiple-empty-lines": ["warn", {
"no-multiple-empty-lines": [ "warn", {
"max": 1,
"maxBOF": 0,
}],
"lines-between-class-members": ["warn", "always", {
"lines-between-class-members": [ "warn", "always", {
exceptAfterSingleLine: true,
}],
"no-unneeded-ternary": "error",
"array-bracket-newline": ["error", "consistent"],
"eol-last": ["error", "always"],
"array-bracket-newline": [ "error", "consistent" ],
"eol-last": [ "error", "always" ],
//'prefer-template': 'error',
"comma-dangle": ["warn", "only-multiline"],
"no-empty": ["error", {
"comma-dangle": [ "warn", "only-multiline" ],
"no-empty": [ "error", {
"allowEmptyCatch": true
}],
"no-control-regex": "off",
"one-var": ["error", "never"],
"max-statements-per-line": ["error", { "max": 1 }]
"one-var": [ "error", "never" ],
"max-statements-per-line": [ "error", { "max": 1 }]
},
"overrides": [
{
"files": [ "src/languages/*.js", "src/icon.js" ],
"rules": {
"comma-dangle": ["error", "always-multiline"],
"comma-dangle": [ "error", "always-multiline" ],
}
},

View File

@@ -1,7 +1,7 @@
name: 🚀 Feature Request
description: "Submit a proposal for a new feature"
#title: "[Feature] "
labels: [enhancement]
labels: [feature-request]
body:
- type: checkboxes
id: no-duplicate-issues

View File

@@ -4,10 +4,10 @@ Fixes #(issue)
## Type of change
Please delete options that are not relevant.
Please delete any options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- User Interface
- User interface (UI)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- Translation update
@@ -18,11 +18,11 @@ Please delete options that are not relevant.
- [ ] My code follows the style guidelines of this project
- [ ] I ran ESLint and other linters for modified files
- [ ] I have performed a self-review of my own code and test it
- [ ] I have performed a self-review of my own code and tested it
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] My changes generate no new warnings
- [ ] My code needed automated testing. I have added them (this is optional task)
## Screenshots (if any)
Please do not use any external image service. Instead, just paste in or drag and drop the image here and it will be uploaded automatically.
Please do not use any external image service. Instead, just paste in or drag and drop the image here, and it will be uploaded automatically.

View File

@@ -20,6 +20,7 @@ jobs:
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}

View File

@@ -0,0 +1,26 @@
name: Close Incorrect Issue
on:
issues:
types: [opened]
jobs:
close-incorrect-issue:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: node extra/close-incorrect-issue.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.issue.number }} ${{ github.event.issue.user.login }}

View File

@@ -1,22 +0,0 @@
name: 'Automatically close stale issues and PRs'
on:
schedule:
- cron: '0 0 * * *'
#Run once a day at midnight
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v4
with:
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
days-before-stale: 180
days-before-close: 7
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,'
exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,'
exempt-issue-assignees: 'louislam'
exempt-pr-assignees: 'louislam'

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
legacy-peer-deps=true

View File

@@ -1,9 +1,13 @@
{
"extends": "stylelint-config-standard",
"customSyntax": "postcss-html",
"rules": {
"indentation": 4,
"no-descending-specificity": null,
"selector-list-comma-newline-after": null,
"declaration-empty-line-before": null
"declaration-empty-line-before": null,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"shorthand-property-no-redundant-values": null
}
}

View File

@@ -1,8 +1,8 @@
# Project Info
First of all, thank you everyone who made pull requests for Uptime Kuma, I never thought GitHub Community can be that nice! And also because of this, I also never thought other people actually read my code and edit my code. It is not structed and commented so well, lol. Sorry about that.
First of all, thank you everyone who made pull requests for Uptime Kuma, I never thought GitHub Community can be that nice! And also because of this, I also never thought other people actually read my code and edit my code. It is not structured and commented so well, lol. Sorry about that.
The project was created with vite.js (vue3). Then I created a sub-directory called "server" for server part. Both frontend and backend share the same package.json.
The project was created with vite.js (vue3). Then I created a subdirectory called "server" for server part. Both frontend and backend share the same package.json.
The frontend code build into "dist" directory. The server (express.js) exposes the "dist" directory as root of the endpoint. This is how production is working.
@@ -27,13 +27,25 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
## Can I create a pull request for Uptime Kuma?
Generally, if the pull request is working fine and it do not affect any existing logic, workflow and perfomance, I will merge into the master branch once it is tested.
⚠️ 2022-03-02 Update:
If you are not sure whether I will accept your pull request, feel free to create an empty pull request draft first.
Since I found that merging pull requests is a pretty heavy task for me, I try to rearrange it.
✅ Accept:
- Bug/Security fix
- Translations
- Adding notification providers
❌ Avoid:
- Large pull requests
- New big features
My long story here: https://www.reddit.com/r/UptimeKuma/comments/t1t6or/comment/hynyijx/
### Recommended Pull Request Guideline
Before deep into coding, disscussion first is preferred. Creating an empty pull request for disscussion would be recommended.
1. Fork the project
1. Clone your fork repo to local
1. Create a new branch
@@ -41,45 +53,9 @@ If you are not sure whether I will accept your pull request, feel free to create
`git commit -m "[empty commit] pull request for <YOUR TASK NAME>" --allow-empty`
1. Push to your fork repo
1. Create a pull request: https://github.com/louislam/uptime-kuma/compare
1. Write a proper description
1. Write a proper description
1. Click "Change to draft"
### Pull Request Examples
Here are some example situations in the past.
#### ✅ High - Medium Priority
Easy to review, no breaking change and not touching the existing code
- Add a new notification
- Add a chart
- Fix a bug
- Translations
- Add a independent new feature
#### *️⃣ Requires one more reviewer
I do not have such knowledge to test it.
- Add k8s supports
#### ⚠ Low Priority - Harsh Mode
Some pull requests are required to modifiy the core. To be honest, I do not want anyone to try to do that, because it would spend a lot of your time. I will review your pull request harshly. Also you may need to write a lot of unit tests to ensure that there is no breaking change.
- Touch large parts of code of any very important features
- Touch monitoring logic
- Drop a table or drop a column for any reason
- Touch the entry point of Docker or Node.js
- Modifiy auth
#### *️⃣ Low Priority
It changed my current workflow and require further studies.
- Change my release approach
1. Discussion
#### ❌ Won't Merge
@@ -114,7 +90,7 @@ I personally do not like something need to learn so much and need to config so m
- Node.js >= 14
- Git
- IDE that supports ESLint and EditorConfig (I am using Intellji Idea)
- IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA)
- A SQLite tool (SQLite Expert Personal is suggested)
## Install dependencies
@@ -141,9 +117,9 @@ express.js is just used for serving the frontend built files (index.html, .js an
- model/ (Object model, auto mapping to the database table name)
- modules/ (Modified 3rd-party modules)
- notification-providers/ (indivdual notification logic)
- notification-providers/ (individual notification logic)
- routers/ (Express Routers)
- scoket-handler (Socket.io Handlers)
- socket-handler (Socket.io Handlers)
- server.js (Server main logic)
## How to start the Frontend Dev Server
@@ -201,7 +177,7 @@ ncu -u -t patch
npm install
```
Since previously updating vite 2.5.10 to 2.6.0 broke the application completely, from now on, it should update patch release version only.
Since previously updating Vite 2.5.10 to 2.6.0 broke the application completely, from now on, it should update patch release version only.
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
@@ -209,47 +185,56 @@ Patch release = the third digit ([Semantic Versioning](https://semver.org/))
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
## Wiki
Since there is no way to make a pull request to wiki's repo, I have setup another repo to do that.
Since there is no way to make a pull request to wiki's repo, I have set up another repo to do that.
https://github.com/louislam/uptime-kuma-wiki
## Maintainer
## Maintainer
Check the latest issues and pull requests:
https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
### Release Procedures
1. Draft a release note
1. Make sure the repo is cleared
1. `npm run update-version 1.X.X`
1. `npm run build`
1. `npm run build-docker`
1. `git push`
1. Publish the release note as 1.X.X
1. `npm run upload-artifacts`
1. SSH to demo site server and update to 1.X.X
2. Make sure the repo is cleared
3. `npm run release-final with env vars: `VERSION` and `GITHUB_TOKEN`
4. Wait until the `Press any key to continue`
5. `git push`
6. Publish the release note as 1.X.X
7. Press any key to continue
8. SSH to demo site server and update to 1.X.X
Checking:
- Check all tags is fine on https://hub.docker.com/r/louislam/uptime-kuma/tags
- Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / armv7)
- Try clean install with Node.js
- Try clean installation with Node.js
### Release Beta Procedures
1. Draft a release note, check "This is a pre-release"
2. Make sure the repo is cleared
3. `npm run release-beta` with env vars: `VERSION` and `GITHUB_TOKEN`
4. Wait until the `Press any key to continue`
5. Publish the release note as 1.X.X-beta.X
6. Press any key to continue
### Release Wiki
#### Setup Repo
```
```bash
git clone https://github.com/louislam/uptime-kuma-wiki.git
cd uptime-kuma-wiki
git remote add production https://github.com/louislam/uptime-kuma.wiki.git
```
#### Push to Production Wiki
```
```bash
git pull
git push production master
```

View File

@@ -17,13 +17,13 @@ Try it!
https://demo.uptime.kuma.pet
It is a temporary live demo, all data will be deleted after 10 minutes. The server is located at Tokyo, so if you live far from there it may affect your experience. I suggest that you should install and try it out for the best demo experience.
It is a temporary live demo, all data will be deleted after 10 minutes. The server is located in Tokyo, so if you live far from there, it may affect your experience. I suggest that you should install and try it out for the best demo experience.
VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollective.com/uptime-kuma)! Thank you so much!
## ⭐ Features
* Monitoring uptime for HTTP(s) / TCP / Ping / DNS Record / Push.
* Monitoring uptime for HTTP(s) / TCP / HTTP(s) Keyword / Ping / DNS Record / Push / Steam Game Server.
* Fancy, Reactive, Fast UI/UX.
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [70+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications).
* 20 second intervals.
@@ -37,15 +37,19 @@ VPS is sponsored by Uptime Kuma sponsors on [Open Collective](https://opencollec
### 🐳 Docker
```bash
docker volume create uptime-kuma
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1
```
⚠️ Please use a **local volume** only. Other types such as NFS are not supported.
Browse to http://localhost:3001 after starting.
### 💪🏻 Non-Docker
Required Tools: Node.js >= 14, git and pm2.
Required Tools:
- [Node.js](https://nodejs.org/en/download/) >= 14
- [Git](https://git-scm.com/downloads)
- [pm2](https://pm2.keymetrics.io/) - For run in background
```bash
# Update your npm to the latest version
@@ -59,15 +63,29 @@ npm run setup
node server/server.js
# (Recommended) Option 2. Run in background using PM2
# Install PM2 if you don't have it: npm install pm2 -g
pm2 start server/server.js --name uptime-kuma
```
# Install PM2 if you don't have it:
npm install pm2 -g && pm2 install pm2-logrotate
# Start Server
pm2 start server/server.js --name uptime-kuma
```
Browse to http://localhost:3001 after starting.
More useful PM2 Commands
```bash
# If you want to see the current console output
pm2 monit
# If you want to add it to startup
pm2 save && pm2 startup
```
### Advanced Installation
If you need more options or need to browse via a reserve proxy, please read:
If you need more options or need to browse via a reverse proxy, please read:
https://github.com/louislam/uptime-kuma/wiki/%F0%9F%94%A7-How-to-Install
@@ -87,6 +105,12 @@ Project Plan:
https://github.com/louislam/uptime-kuma/projects/1
## ❤️ Sponsors
Thank you so much! (GitHub Sponsors will be updated manually. OpenCollective sponsors will be updated automatically, the list will be cached by GitHub though. It may need some time to be updated)
<img src="https://uptime.kuma.pet/sponsors?v=6" alt />
## 🖼 More Screenshots
Light Mode:
@@ -107,7 +131,7 @@ Telegram Notification Sample:
## Motivation
* I was looking for a self-hosted monitoring tool like "Uptime Robot", but it is hard to find a suitable one. One of the close ones is statping. Unfortunately, it is not stable and unmaintained.
* I was looking for a self-hosted monitoring tool like "Uptime Robot", but it is hard to find a suitable one. One of the close ones is statping. Unfortunately, it is not stable and no longer maintained.
* Want to build a fancy UI.
* Learn Vue 3 and vite.js.
* Show the power of Bootstrap 5.
@@ -120,7 +144,7 @@ If you love this project, please consider giving me a ⭐.
### Issues Page
You can discuss or ask for help in [Issues](https://github.com/louislam/uptime-kuma/issues).
You can discuss or ask for help in [issues](https://github.com/louislam/uptime-kuma/issues).
### Subreddit
@@ -130,10 +154,17 @@ https://www.reddit.com/r/UptimeKuma/
## Contribute
### Test Beta Version
Check out the latest beta release here: https://github.com/louislam/uptime-kuma/releases
### Bug Reports / Feature Requests
If you want to report a bug or request a new feature. Free feel to open a [new issue](https://github.com/louislam/uptime-kuma/issues).
If you want to translate Uptime Kuma into your langauge, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
## Translations
If you want to translate Uptime Kuma into your language, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
Feel free to correct my grammar in this README, source code, or wiki, as my mother language is not English and my grammar is not that great.
## Pull Requests
If you want to modify Uptime Kuma, this guideline may be useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md
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.

View File

@@ -1,11 +1,11 @@
const config = {};
if (process.env.TEST_FRONTEND) {
config.presets = ["@babel/preset-env"];
config.presets = [ "@babel/preset-env" ];
}
if (process.env.TEST_BACKEND) {
config.plugins = ["babel-plugin-rewire"];
config.plugins = [ "babel-plugin-rewire" ];
}
module.exports = config;

33
config/jest-debug-env.js Normal file
View File

@@ -0,0 +1,33 @@
const PuppeteerEnvironment = require("jest-environment-puppeteer");
const util = require("util");
class DebugEnv extends PuppeteerEnvironment {
async handleTestEvent(event, state) {
const ignoredEvents = [
"setup",
"add_hook",
"start_describe_definition",
"add_test",
"finish_describe_definition",
"run_start",
"run_describe_start",
"test_start",
"hook_start",
"hook_success",
"test_fn_start",
"test_fn_success",
"test_done",
"run_describe_finish",
"run_finish",
"teardown",
"test_fn_failure",
];
if (!ignoredEvents.includes(event.name)) {
console.log(
new Date().toString() + ` Unhandled event [${event.name}] ` + util.inspect(event)
);
}
}
}
module.exports = DebugEnv;

View File

@@ -1,6 +1,20 @@
module.exports = {
"launch": {
"dumpio": true,
"slowMo": 500,
"headless": process.env.HEADLESS_TEST || false,
"userDataDir": "./data/test-chrome-profile",
args: [
"--disable-setuid-sandbox",
"--disable-gpu",
"--disable-dev-shm-usage",
"--no-default-browser-check",
"--no-experiments",
"--no-first-run",
"--no-pings",
"--no-sandbox",
"--no-zygote",
"--single-process",
],
}
};

View File

@@ -5,6 +5,7 @@ module.exports = {
"__DEV__": true
},
"testRegex": "./test/e2e.spec.js",
"testEnvironment": "./config/jest-debug-env.js",
"rootDir": "..",
"testTimeout": 30000,
};

View File

@@ -10,15 +10,15 @@ export default defineConfig({
plugins: [
vue(),
legacy({
targets: ["ie > 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
targets: [ "ie > 11" ],
additionalLegacyPolyfills: [ "regenerator-runtime/runtime" ]
})
],
css: {
postcss: {
"parser": postCssScss,
"map": false,
"plugins": [postcssRTLCSS]
"plugins": [ postcssRTLCSS ]
}
},
});

View File

@@ -0,0 +1,16 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD mqtt_topic TEXT;
ALTER TABLE monitor
ADD mqtt_success_message VARCHAR(255);
ALTER TABLE monitor
ADD mqtt_username VARCHAR(255);
ALTER TABLE monitor
ADD mqtt_password VARCHAR(255);
COMMIT;

View File

@@ -0,0 +1,10 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD basic_auth_user TEXT default null;
ALTER TABLE monitor
ADD basic_auth_pass TEXT default null;
COMMIT;

View File

@@ -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 expiry_notification BOOLEAN default 1;
COMMIT;

23
db/patch-proxy.sql Normal file
View File

@@ -0,0 +1,23 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
CREATE TABLE proxy (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
user_id INT NOT NULL,
protocol VARCHAR(10) NOT NULL,
host VARCHAR(255) NOT NULL,
port SMALLINT NOT NULL,
auth BOOLEAN NOT NULL,
username VARCHAR(255) NULL,
password VARCHAR(255) NULL,
active BOOLEAN NOT NULL DEFAULT 1,
'default' BOOLEAN NOT NULL DEFAULT 0,
created_date DATETIME DEFAULT (DATETIME('now')) NOT NULL
);
ALTER TABLE monitor ADD COLUMN proxy_id INTEGER REFERENCES proxy(id);
CREATE INDEX proxy_id ON monitor (proxy_id);
CREATE INDEX proxy_user_id ON proxy (user_id);
COMMIT;

View File

@@ -0,0 +1,6 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE status_page ADD footer_text TEXT;
ALTER TABLE status_page ADD custom_css TEXT;
ALTER TABLE status_page ADD show_powered_by BOOLEAN NOT NULL DEFAULT 1;
COMMIT;

31
db/patch-status-page.sql Normal file
View File

@@ -0,0 +1,31 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
CREATE TABLE [status_page](
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
[slug] VARCHAR(255) NOT NULL UNIQUE,
[title] VARCHAR(255) NOT NULL,
[description] TEXT,
[icon] VARCHAR(255) NOT NULL,
[theme] VARCHAR(30) NOT NULL,
[published] BOOLEAN NOT NULL DEFAULT 1,
[search_engine_index] BOOLEAN NOT NULL DEFAULT 1,
[show_tags] BOOLEAN NOT NULL DEFAULT 0,
[password] VARCHAR,
[created_date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
[modified_date] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX [slug] ON [status_page]([slug]);
CREATE TABLE [status_page_cname](
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
[status_page_id] INTEGER NOT NULL REFERENCES [status_page]([id]) ON DELETE CASCADE ON UPDATE CASCADE,
[domain] VARCHAR NOT NULL UNIQUE
);
ALTER TABLE incident ADD status_page_id INTEGER;
ALTER TABLE [group] ADD status_page_id INTEGER;
COMMIT;

View File

@@ -1,8 +1,8 @@
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
FROM node:14-alpine3.12
FROM node:16-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 && \
pip3 --no-cache-dir install apprise==0.9.7 && \
rm -rf /root/.cache

View File

@@ -1,12 +1,26 @@
# 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
FROM node:16-buster-slim
ARG TARGETPLATFORM
WORKDIR /app
# Install Curl
# 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!
# Stupid python3 and python3-pip actually install a lot of useless things into Debian, specify --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 && \
pip3 --no-cache-dir install apprise==0.9.7 && \
rm -rf /var/lib/apt/lists/*
# Install cloudflared
# dpkg --add-architecture arm: cloudflared do not provide armhf, this is workaround. Read more: https://github.com/cloudflare/cloudflared/issues/583
COPY extra/download-cloudflared.js ./extra/download-cloudflared.js
RUN node ./extra/download-cloudflared.js $TARGETPLATFORM && \
dpkg --add-architecture arm && \
apt update && \
apt --yes --no-install-recommends install ./cloudflared.deb && \
rm -rf /var/lib/apt/lists/* && \
rm -f cloudflared.deb

View File

@@ -5,9 +5,10 @@ version: '3.3'
services:
uptime-kuma:
image: louislam/uptime-kuma
image: louislam/uptime-kuma:1
container_name: uptime-kuma
volumes:
- ./uptime-kuma:/app/data
ports:
- 3001:3001
restart: always

View File

@@ -33,7 +33,7 @@ RUN apt update && \
COPY --from=build /app /app
ARG VERSION=1.9.1
ARG VERSION
ARG GITHUB_TOKEN
ARG TARGETARCH
ARG PLATFORM=debian

View File

@@ -1,6 +1,6 @@
module.exports = {
apps: [{
name: "uptime-kuma",
script: "./server/server.js",
}]
}
apps: [{
name: "uptime-kuma",
script: "./server/server.js",
}]
};

View File

@@ -0,0 +1,62 @@
const pkg = require("../../package.json");
const fs = require("fs");
const childProcess = require("child_process");
const util = require("../../src/util");
util.polyfill();
const version = process.env.VERSION;
console.log("Beta Version: " + version);
if (!version || !version.includes("-beta.")) {
console.error("invalid version, beta version only");
process.exit(1);
}
const exists = tagExists(version);
if (! exists) {
// Process package.json
pkg.version = version;
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
commit(version);
tag(version);
} else {
console.log("version tag exists, please delete the tag or use another tag");
process.exit(1);
}
function commit(version) {
let msg = "Update to " + version;
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
let stdout = res.stdout.toString().trim();
console.log(stdout);
if (stdout.includes("no changes added to commit")) {
throw new Error("commit error");
}
res = childProcess.spawnSync("git", [ "push", "origin", "master" ]);
console.log(res.stdout.toString().trim());
}
function tag(version) {
let res = childProcess.spawnSync("git", [ "tag", version ]);
console.log(res.stdout.toString().trim());
res = childProcess.spawnSync("git", [ "push", "origin", version ]);
console.log(res.stdout.toString().trim());
}
function tagExists(version) {
if (! version) {
throw new Error("invalid version");
}
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
return res.stdout.toString().trim() === version;
}

View File

@@ -0,0 +1,57 @@
const github = require("@actions/github");
(async () => {
try {
const token = process.argv[2];
const issueNumber = process.argv[3];
const username = process.argv[4];
const client = github.getOctokit(token).rest;
const issue = {
owner: "louislam",
repo: "uptime-kuma",
number: issueNumber,
};
const labels = (
await client.issues.listLabelsOnIssue({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number
})
).data.map(({ name }) => name);
if (labels.length === 0) {
console.log("Bad format here");
await client.issues.addLabels({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
labels: [ "invalid-format" ]
});
// Add the issue closing comment
await client.issues.createComment({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please DO NOT open a blank issue.`
});
// Close the issue
await client.issues.update({
owner: issue.owner,
repo: issue.repo,
issue_number: issue.number,
state: "closed"
});
} else {
console.log("Pass!");
}
} catch (e) {
console.log(e);
}
})();

View File

@@ -0,0 +1,44 @@
//
const http = require("https"); // or 'https' for https:// URLs
const fs = require("fs");
const platform = process.argv[2];
if (!platform) {
console.error("No platform??");
process.exit(1);
}
let arch = null;
if (platform === "linux/amd64") {
arch = "amd64";
} else if (platform === "linux/arm64") {
arch = "arm64";
} else if (platform === "linux/arm/v7") {
arch = "arm";
} else {
console.error("Invalid platform?? " + platform);
}
const file = fs.createWriteStream("cloudflared.deb");
get("https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-" + arch + ".deb");
function get(url) {
http.get(url, function (res) {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
console.log("Redirect to " + res.headers.location);
get(res.headers.location);
} else if (res.statusCode >= 200 && res.statusCode < 300) {
res.pipe(file);
res.on("end", function () {
console.log("Downloaded");
});
} else {
console.error(res.statusCode);
process.exit(1);
}
});
}

View File

@@ -4,6 +4,7 @@ const tar = require("tar");
const packageJSON = require("../package.json");
const fs = require("fs");
const rmSync = require("./fs-rmSync.js");
const version = packageJSON.version;
const filename = "dist.tar.gz";
@@ -11,6 +12,12 @@ const filename = "dist.tar.gz";
const url = `https://github.com/louislam/uptime-kuma/releases/download/${version}/${filename}`;
download(url);
/**
* Downloads the latest version of the dist from a GitHub release.
* @param {string} url The URL to download from.
*
* Generated by Trelent
*/
function download(url) {
console.log(url);
@@ -21,7 +28,7 @@ function download(url) {
if (fs.existsSync("./dist")) {
if (fs.existsSync("./dist-backup")) {
fs.rmdirSync("./dist-backup", {
rmSync("./dist-backup", {
recursive: true
});
}
@@ -35,7 +42,7 @@ function download(url) {
tarStream.on("close", () => {
if (fs.existsSync("./dist-backup")) {
fs.rmdirSync("./dist-backup", {
rmSync("./dist-backup", {
recursive: true
});
}

19
extra/env2arg.js Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
const childProcess = require("child_process");
let env = process.env;
let cmd = process.argv[2];
let args = process.argv.slice(3);
let replacedArgs = [];
for (let arg of args) {
for (let key in env) {
arg = arg.replaceAll(`$${key}`, env[key]);
}
replacedArgs.push(arg);
}
let child = childProcess.spawn(cmd, replacedArgs);
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

23
extra/fs-rmSync.js Normal file
View File

@@ -0,0 +1,23 @@
const fs = require("fs");
/**
* Detect if `fs.rmSync` is available
* to avoid the runtime deprecation warning triggered for using `fs.rmdirSync` with `{ recursive: true }` in Node.js v16,
* or the `recursive` property removing completely in the future Node.js version.
* See the link below.
*
* @todo Once we drop the support for Node.js v14 (or at least versions before v14.14.0), we can safely replace this function with `fs.rmSync`, since `fs.rmSync` was add in Node.js v14.14.0 and currently we supports all the Node.js v14 versions that include the versions before the v14.14.0, and this function have almost the same signature with `fs.rmSync`.
* @link https://nodejs.org/docs/latest-v16.x/api/deprecations.html#dep0147-fsrmdirpath--recursive-true- the deprecation infomation of `fs.rmdirSync`
* @link https://nodejs.org/docs/latest-v16.x/api/fs.html#fsrmsyncpath-options the document of `fs.rmSync`
* @param {fs.PathLike} path Valid types for path values in "fs".
* @param {fs.RmDirOptions} [options] options for `fs.rmdirSync`, if `fs.rmSync` is available and property `recursive` is true, it will automatically have property `force` with value `true`.
*/
const rmSync = (path, options) => {
if (typeof fs.rmSync === "function") {
if (options.recursive) {
options.force = true;
}
return fs.rmSync(path, options);
}
return fs.rmdirSync(path, options);
};
module.exports = rmSync;

View File

@@ -20,7 +20,7 @@ if (sslKey && sslCert) {
// Dual-stack support for (::)
let hostname = process.env.UPTIME_KUMA_HOST;
// Also read HOST if not FreeBSD, as HOST is a system environment variable in FreeBSD
// Also read HOST if not *BSD, as HOST is a system environment variable in FreeBSD
if (!hostname && !FBSD) {
hostname = process.env.HOST;
}

View File

@@ -189,7 +189,7 @@ if (type == "local") {
bash("check=$(pm2 --version)");
if (check == "") {
println("Installing PM2");
bash("npm install pm2 -g");
bash("npm install pm2 -g && pm2 install pm2-logrotate");
bash("pm2 startup");
}

View File

@@ -4,21 +4,21 @@ const util = require("../src/util");
util.polyfill();
const oldVersion = pkg.version
const newVersion = oldVersion + "-nightly"
const oldVersion = pkg.version;
const newVersion = oldVersion + "-nightly";
console.log("Old Version: " + oldVersion)
console.log("New Version: " + newVersion)
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")
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))
fs.writeFileSync("README.md", fs.readFileSync("README.md", "utf8").replaceAll(oldVersion, newVersion));
}
}

6
extra/press-any-key.js Normal file
View File

@@ -0,0 +1,6 @@
console.log("Git Push and Publish the release note on github, then press any key to continue");
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on("data", process.exit.bind(process, 0));

60
extra/remove-2fa.js Normal file
View File

@@ -0,0 +1,60 @@
console.log("== Uptime Kuma Remove 2FA Tool ==");
console.log("Loading the database");
const Database = require("../server/database");
const { R } = require("redbean-node");
const readline = require("readline");
const TwoFA = require("../server/2fa");
const args = require("args-parser")(process.argv);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const main = async () => {
Database.init(args);
await Database.connect();
try {
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
if (!process.env.TEST_BACKEND) {
const user = await R.findOne("user");
if (! user) {
throw new Error("user not found, have you installed?");
}
console.log("Found user: " + user.username);
let ans = await question("Are you sure want to remove 2FA? [y/N]");
if (ans.toLowerCase() === "y") {
await TwoFA.disable2FA(user.id);
console.log("2FA has been removed successfully.");
}
}
} catch (e) {
console.error("Error: " + e.message);
}
await Database.close();
rl.close();
console.log("Finished.");
};
function question(question) {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
if (!process.env.TEST_BACKEND) {
main();
}
module.exports = {
main,
};

View File

@@ -1,11 +1,10 @@
console.log("== Uptime Kuma Reset Password Tool ==");
console.log("Loading the database");
const Database = require("../server/database");
const { R } = require("redbean-node");
const readline = require("readline");
const { initJWTSecret } = require("../server/util-server");
const User = require("../server/model/user");
const args = require("args-parser")(process.argv);
const rl = readline.createInterface({
input: process.stdin,
@@ -13,8 +12,9 @@ const rl = readline.createInterface({
});
const main = async () => {
console.log("Connecting the database");
Database.init(args);
await Database.connect();
await Database.connect(false, false, true);
try {
// No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
@@ -31,7 +31,7 @@ const main = async () => {
let confirmPassword = await question("Confirm New Password: ");
if (password === confirmPassword) {
await user.resetPassword(password);
await User.resetPassword(user.id, password);
// Reset all sessions by reset jwt secret
await initJWTSecret();

View File

@@ -26,7 +26,7 @@ server.on("request", (request, send, rinfo) => {
ttl: 300,
address: "1.2.3.4"
});
} if (question.type === Packet.TYPE.AAAA) {
} else if (question.type === Packet.TYPE.AAAA) {
response.answers.push({
name: question.name,
type: question.type,

View File

@@ -0,0 +1,50 @@
const { log } = require("../src/util");
const mqttUsername = "louis1";
const mqttPassword = "!@#$LLam";
class SimpleMqttServer {
aedes = require("aedes")();
server = require("net").createServer(this.aedes.handle);
constructor(port) {
this.port = port;
}
start() {
this.server.listen(this.port, () => {
console.log("server started and listening on port ", this.port);
});
}
}
let server1 = new SimpleMqttServer(10000);
server1.aedes.authenticate = function (client, username, password, callback) {
if (username && password) {
console.log(password.toString("utf-8"));
callback(null, username === mqttUsername && password.toString("utf-8") === mqttPassword);
} else {
callback(null, false);
}
};
server1.aedes.on("subscribe", (subscriptions, client) => {
console.log(subscriptions);
for (let s of subscriptions) {
if (s.topic === "test") {
server1.aedes.publish({
topic: "test",
payload: Buffer.from("ok"),
}, (error) => {
if (error) {
log.error("mqtt_server", error);
}
});
}
}
});
server1.start();

View File

@@ -3,6 +3,7 @@
import fs from "fs";
import path from "path";
import util from "util";
import rmSync from "../fs-rmSync.js";
// https://stackoverflow.com/questions/13786160/copy-folder-recursively-in-node-js
/**
@@ -30,7 +31,7 @@ console.log("Arguments:", process.argv);
const baseLangCode = process.argv[2] || "en";
console.log("Base Lang: " + baseLangCode);
if (fs.existsSync("./languages")) {
fs.rmdirSync("./languages", { recursive: true });
rmSync("./languages", { recursive: true });
}
copyRecursiveSync("../../src/languages", "./languages");
@@ -40,7 +41,7 @@ const files = fs.readdirSync("./languages");
console.log("Files:", files);
for (const file of files) {
if (!file.endsWith(".js")) {
if (! file.endsWith(".js")) {
console.log("Skipping " + file);
continue;
}
@@ -82,5 +83,5 @@ for (const file of files) {
fs.writeFileSync(`../../src/languages/${file}`, code);
}
fs.rmdirSync("./languages", { recursive: true });
rmSync("./languages", { recursive: true });
console.log("Done. Fixing formatting by ESLint...");

View File

@@ -1,14 +1,12 @@
const pkg = require("../package.json");
const fs = require("fs");
const child_process = require("child_process");
const childProcess = require("child_process");
const util = require("../src/util");
util.polyfill();
const oldVersion = pkg.version;
const newVersion = process.argv[2];
const newVersion = process.env.VERSION;
console.log("Old Version: " + oldVersion);
console.log("New Version: " + newVersion);
if (! newVersion) {
@@ -22,25 +20,28 @@ if (! exists) {
// 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);
pkg.scripts["build-docker-alpine"] = pkg.scripts["build-docker-alpine"].replaceAll(oldVersion, newVersion);
pkg.scripts["build-docker-debian"] = pkg.scripts["build-docker-debian"].replaceAll(oldVersion, newVersion);
// Replace the version: https://regex101.com/r/hmj2Bc/1
pkg.scripts.setup = pkg.scripts.setup.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
commit(newVersion);
tag(newVersion);
updateWiki(oldVersion, newVersion);
} else {
console.log("version exists");
}
/**
* Updates the version number in package.json and commits it to git.
* @param {string} version - The new version number
*
* Generated by Trelent
*/
function commit(version) {
let msg = "update to " + version;
let msg = "Update to " + version;
let res = child_process.spawnSync("git", ["commit", "-m", msg, "-a"]);
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
let stdout = res.stdout.toString().trim();
console.log(stdout);
@@ -50,51 +51,22 @@ function commit(version) {
}
function tag(version) {
let res = child_process.spawnSync("git", ["tag", version]);
let res = childProcess.spawnSync("git", [ "tag", version ]);
console.log(res.stdout.toString().trim());
}
/**
* Checks if a given version is already tagged in the git repository.
* @param {string} version - The version to check for.
*
* Generated by Trelent
*/
function tagExists(version) {
if (! version) {
throw new Error("invalid version");
}
let res = child_process.spawnSync("git", ["tag", "-l", version]);
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
return res.stdout.toString().trim() === version;
}
function updateWiki(oldVersion, newVersion) {
const wikiDir = "./tmp/wiki";
const howToUpdateFilename = "./tmp/wiki/🆙-How-to-Update.md";
safeDelete(wikiDir);
child_process.spawnSync("git", ["clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir]);
let content = fs.readFileSync(howToUpdateFilename).toString();
content = content.replaceAll(`git checkout ${oldVersion}`, `git checkout ${newVersion}`);
fs.writeFileSync(howToUpdateFilename, content);
child_process.spawnSync("git", ["add", "-A"], {
cwd: wikiDir,
});
child_process.spawnSync("git", ["commit", "-m", `Update to ${newVersion} from ${oldVersion}`], {
cwd: wikiDir,
});
console.log("Pushing to Github");
child_process.spawnSync("git", ["push"], {
cwd: wikiDir,
});
safeDelete(wikiDir);
}
function safeDelete(dir) {
if (fs.existsSync(dir)) {
fs.rmdirSync(dir, {
recursive: true,
});
}
}

View File

@@ -0,0 +1,48 @@
const childProcess = require("child_process");
const fs = require("fs");
const newVersion = process.env.VERSION;
if (!newVersion) {
console.log("Missing version");
process.exit(1);
}
updateWiki(newVersion);
function updateWiki(newVersion) {
const wikiDir = "./tmp/wiki";
const howToUpdateFilename = "./tmp/wiki/🆙-How-to-Update.md";
safeDelete(wikiDir);
childProcess.spawnSync("git", [ "clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir ]);
let content = fs.readFileSync(howToUpdateFilename).toString();
// Replace the version: https://regex101.com/r/hmj2Bc/1
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
fs.writeFileSync(howToUpdateFilename, content);
childProcess.spawnSync("git", [ "add", "-A" ], {
cwd: wikiDir,
});
childProcess.spawnSync("git", [ "commit", "-m", `Update to ${newVersion}` ], {
cwd: wikiDir,
});
console.log("Pushing to Github");
childProcess.spawnSync("git", [ "push" ], {
cwd: wikiDir,
});
safeDelete(wikiDir);
}
function safeDelete(dir) {
if (fs.existsSync(dir)) {
fs.rmdirSync(dir, {
recursive: true,
});
}
}

View File

@@ -159,7 +159,7 @@ fi
check=$(pm2 --version)
if [ "$check" == "" ]; then
"echo" "-e" "Installing PM2"
npm install pm2 -g
npm install pm2 -g && pm2 install pm2-logrotate
pm2 startup
fi
mkdir -p $installPath

14707
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,19 @@
{
"name": "uptime-kuma",
"version": "1.10.1",
"version": "1.15.0-beta.1",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/louislam/uptime-kuma.git"
},
"engines": {
"node": "14.*"
"node": "14.* || >=16.*"
},
"scripts": {
"install-legacy": "npm install --legacy-peer-deps",
"update-legacy": "npm update --legacy-peer-deps",
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
"lint": "npm run lint:js && npm run lint:style",
"dev": "vite --host --config ./config/vite.config.js",
@@ -20,27 +21,27 @@
"start-server": "node server/server.js",
"start-server-dev": "cross-env NODE_ENV=development node server/server.js",
"build": "vite build --config ./config/vite.config.js",
"test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test",
"test": "npm run lint && node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --test",
"test-with-build": "npm run build && npm test",
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend && jest --config=./config/jest.config.js",
"jest": "node test/prepare-jest.js && npm run jest-frontend && npm run jest-backend",
"jest-frontend": "cross-env TEST_FRONTEND=1 jest --config=./config/jest-frontend.config.js",
"jest-backend": "cross-env TEST_BACKEND=1 jest --config=./config/jest-backend.config.js",
"tsc": "tsc",
"vite-preview-dist": "vite preview --host --config ./config/vite.config.js",
"build-docker": "npm run build-docker-debian && npm run build-docker-alpine",
"build-docker": "npm run build && 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 docker/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.10.1-alpine --target release . --push",
"build-docker-debian": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.10.1 -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:1.10.1-debian --target release . --push",
"build-docker-nightly": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
"build-docker-alpine": "node ./extra/env2arg.js docker buildx build -f docker/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:$VERSION-alpine --target release . --push",
"build-docker-debian": "node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:debian -t louislam/uptime-kuma:1-debian -t louislam/uptime-kuma:$VERSION-debian --target release . --push",
"build-docker-nightly": "npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
"build-docker-nightly-alpine": "docker buildx build -f docker/dockerfile-alpine --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly-alpine --target nightly . --push",
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.10.1 && npm ci --production && npm run download-dist",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.14.1 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js",
"update-version": "node extra/update-version.js",
"mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js",
"remove-2fa": "node extra/remove-2fa.js",
"compile-install-script": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./extra/compile-install-script.ps1",
"test-install-script-centos7": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/centos7.dockerfile .",
"test-install-script-alpine3": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/alpine3.dockerfile .",
@@ -48,84 +49,101 @@
"test-install-script-ubuntu1604": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu1604.dockerfile .",
"test-nodejs16": "docker build --progress plain -f test/ubuntu-nodejs16.dockerfile .",
"simple-dns-server": "node extra/simple-dns-server.js",
"simple-mqtt-server": "node extra/simple-mqtt-server.js",
"update-language-files-with-base-lang": "cd extra/update-language-files && node index.js %npm_config_base_lang% && eslint ../../src/languages/**.js --fix",
"update-language-files": "cd extra/update-language-files && node index.js && eslint ../../src/languages/**.js --fix"
"update-language-files": "cd extra/update-language-files && node index.js && eslint ../../src/languages/**.js --fix",
"ncu-patch": "npm-check-updates -u -t patch",
"release-final": "node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js",
"release-beta": "node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts",
"git-remove-tag": "git tag -d"
},
"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": "~6.0.0",
"@fortawesome/vue-fontawesome": "~3.0.0-5",
"@louislam/sqlite3": "~15.0.3",
"@popperjs/core": "~2.10.2",
"args-parser": "~1.3.0",
"axios": "~0.21.4",
"axios": "~0.26.1",
"bcryptjs": "~2.4.3",
"bootstrap": "5.1.3",
"bree": "~6.3.1",
"bree": "~7.1.5",
"chardet": "^1.3.0",
"chart.js": "~3.6.0",
"chart.js": "~3.6.2",
"chartjs-adapter-dayjs": "~1.0.0",
"check-password-strength": "^2.0.3",
"check-password-strength": "^2.0.5",
"command-exists": "~1.2.9",
"compare-versions": "~3.6.0",
"dayjs": "~1.10.7",
"express": "~4.17.1",
"express-basic-auth": "~1.2.0",
"dayjs": "~1.10.8",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"favico.js": "^0.3.10",
"form-data": "~4.0.0",
"http-graceful-shutdown": "~3.1.4",
"http-graceful-shutdown": "~3.1.7",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",
"iconv-lite": "^0.6.3",
"jsonwebtoken": "~8.5.1",
"jwt-decode": "^3.1.2",
"limiter": "^2.1.0",
"mqtt": "^4.2.8",
"node-cloudflared-tunnel": "~1.0.9",
"nodemailer": "~6.6.5",
"notp": "~2.0.3",
"password-hash": "~1.2.2",
"postcss-rtlcss": "~3.4.1",
"postcss-scss": "~4.0.1",
"postcss-scss": "~4.0.3",
"prismjs": "^1.27.0",
"prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.0",
"qrcode": "~1.4.4",
"prometheus-api-metrics": "~3.2.1",
"qrcode": "~1.5.0",
"redbean-node": "0.1.3",
"socket.io": "~4.2.0",
"socket.io-client": "~4.2.0",
"socket.io": "~4.4.1",
"socket.io-client": "~4.4.1",
"socks-proxy-agent": "^6.1.1",
"tar": "^6.1.11",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"timezones-list": "~3.0.1",
"v-pagination-3": "~0.1.7",
"vue": "next",
"vue-chart-3": "~0.5.11",
"vue-chart-3": "3.0.9",
"vue-confirm-dialog": "~1.0.2",
"vue-contenteditable": "~3.0.4",
"vue-i18n": "~9.1.9",
"vue-image-crop-upload": "~3.0.3",
"vue-multiselect": "~3.0.0-alpha.2",
"vue-prism-editor": "^2.0.0-alpha.2",
"vue-qrcode": "~1.0.0",
"vue-router": "~4.0.11",
"vue-toastification": "~2.0.0-rc.1",
"vue-router": "~4.0.14",
"vue-toastification": "~2.0.0-rc.5",
"vuedraggable": "~4.1.0"
},
"devDependencies": {
"@babel/eslint-parser": "~7.15.7",
"@actions/github": "~5.0.1",
"@babel/eslint-parser": "~7.15.8",
"@babel/preset-env": "^7.15.8",
"@types/bootstrap": "~5.1.6",
"@vitejs/plugin-legacy": "~1.6.2",
"@types/bootstrap": "~5.1.9",
"@vitejs/plugin-legacy": "~1.6.4",
"@vitejs/plugin-vue": "~1.9.4",
"@vue/compiler-sfc": "~3.2.20",
"@vue/compiler-sfc": "~3.2.31",
"aedes": "^0.46.3",
"babel-plugin-rewire": "~1.2.0",
"core-js": "~3.18.1",
"core-js": "~3.18.3",
"cross-env": "~7.0.3",
"dns2": "~2.0.1",
"eslint": "~7.32.0",
"eslint-plugin-vue": "~7.18.0",
"jest": "~27.2.4",
"jest-puppeteer": "~6.0.0",
"puppeteer": "~10.4.0",
"jest": "~27.2.5",
"jest-puppeteer": "~6.0.3",
"npm-check-updates": "^12.5.5",
"postcss-html": "^1.3.1",
"puppeteer": "~13.1.3",
"sass": "~1.42.1",
"stylelint": "~13.13.1",
"stylelint-config-standard": "~22.0.0",
"typescript": "~4.4.3",
"vite": "~2.6.13"
"stylelint": "~14.2.0",
"stylelint-config-standard": "~24.0.0",
"typescript": "~4.4.4",
"vite": "~2.6.14"
}
}

13
server/2fa.js Normal file
View File

@@ -0,0 +1,13 @@
const { R } = require("redbean-node");
class TwoFA {
static async disable2FA(userID) {
return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [
userID,
]);
}
}
module.exports = TwoFA;

View File

@@ -2,7 +2,6 @@ const basicAuth = require("express-basic-auth");
const passwordHash = require("./password-hash");
const { R } = require("redbean-node");
const { setting } = require("./util-server");
const { debug } = require("../src/util");
const { loginRateLimiter } = require("./rate-limiter");
/**
@@ -12,6 +11,10 @@ const { loginRateLimiter } = require("./rate-limiter");
* @returns {Promise<Bean|null>}
*/
exports.login = async function (username, password) {
if (typeof username !== "string" || typeof password !== "string") {
return null;
}
let user = await R.findOne("user", " username = ? AND active = 1 ", [
username,
]);
@@ -30,32 +33,42 @@ exports.login = async function (username, password) {
return null;
};
/**
* A function that checks if a user is logged in.
* @param {string} username The username of the user to check for.
* @param {function} callback The callback to call when done, with an error and result parameter.
*
* Generated by Trelent
*/
function myAuthorizer(username, password, callback) {
setting("disableAuth").then((result) => {
if (result) {
callback(null, true);
} else {
// Login Rate Limit
loginRateLimiter.pass(null, 0).then((pass) => {
if (pass) {
exports.login(username, password).then((user) => {
callback(null, user != null);
// Login Rate Limit
loginRateLimiter.pass(null, 0).then((pass) => {
if (pass) {
exports.login(username, password).then((user) => {
callback(null, user != null);
if (user == null) {
loginRateLimiter.removeTokens(1);
}
});
} else {
callback(null, false);
if (user == null) {
loginRateLimiter.removeTokens(1);
}
});
} else {
callback(null, false);
}
});
}
exports.basicAuth = basicAuth({
authorizer: myAuthorizer,
authorizeAsync: true,
challenge: true,
});
exports.basicAuth = async function (req, res, next) {
const middleware = basicAuth({
authorizer: myAuthorizer,
authorizeAsync: true,
challenge: true,
});
const disabledAuth = await setting("disableAuth");
if (!disabledAuth) {
middleware(req, res, next);
} else {
next();
}
};

View File

@@ -1,5 +1,6 @@
const { setSetting } = require("./util-server");
const { setSetting, setting } = require("./util-server");
const axios = require("axios");
const compareVersions = require("compare-versions");
exports.version = require("../package.json").version;
exports.latestVersion = null;
@@ -16,6 +17,19 @@ exports.startInterval = () => {
res.data.slow = "1000.0.0";
}
if (await setting("checkUpdate") === false) {
return;
}
let checkBeta = await setting("checkBeta");
if (checkBeta && res.data.beta) {
if (compareVersions.compare(res.data.beta, res.data.beta, ">")) {
exports.latestVersion = res.data.beta;
return;
}
}
if (res.data.slow) {
exports.latestVersion = res.data.slow;
}

View File

@@ -3,10 +3,17 @@
*/
const { TimeLogger } = require("../src/util");
const { R } = require("redbean-node");
const { io } = require("./server");
const { UptimeKumaServer } = require("./uptime-kuma-server");
const io = UptimeKumaServer.getInstance().io;
const { setting } = require("./util-server");
const checkVersion = require("./check-version");
/**
* Send a list of notifications to the user.
* @param {Socket} socket The socket object that is connected to the client.
*
* Generated by Trelent
*/
async function sendNotificationList(socket) {
const timeLogger = new TimeLogger();
@@ -83,6 +90,29 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
}
/**
* Delivers proxy list
*
* @param socket
* @return {Promise<Bean[]>}
*/
async function sendProxyList(socket) {
const timeLogger = new TimeLogger();
const list = await R.find("proxy", " user_id = ? ", [ socket.userID ]);
io.to(socket.userID).emit("proxyList", list.map(bean => bean.export()));
timeLogger.print("Send Proxy List");
return list;
}
/**
* Emits the version information to the client.
* @param {Socket} socket The socket object that is connected to the client.
*
* Generated by Trelent
*/
async function sendInfo(socket) {
socket.emit("info", {
version: checkVersion.version,
@@ -95,6 +125,6 @@ module.exports = {
sendNotificationList,
sendImportantHeartbeatList,
sendHeartbeatList,
sendInfo
sendProxyList,
sendInfo,
};

View File

@@ -1,7 +1,7 @@
const fs = require("fs");
const { R } = require("redbean-node");
const { setSetting, setting } = require("./util-server");
const { debug, sleep } = require("../src/util");
const { log, sleep } = require("../src/util");
const dayjs = require("dayjs");
const knex = require("knex");
@@ -52,6 +52,12 @@ class Database {
"patch-http-monitor-method-body-and-headers.sql": true,
"patch-2fa-invalidate-used-token.sql": true,
"patch-notification_sent_history.sql": true,
"patch-monitor-basic-auth.sql": true,
"patch-status-page.sql": true,
"patch-proxy.sql": true,
"patch-monitor-expiry-notification.sql": true,
"patch-status-page-footer-css.sql": true,
"patch-added-mqtt-monitor.sql": true,
}
/**
@@ -76,10 +82,10 @@ class Database {
fs.mkdirSync(Database.uploadDir, { recursive: true });
}
console.log(`Data Dir: ${Database.dataDir}`);
log.info("db", `Data Dir: ${Database.dataDir}`);
}
static async connect() {
static async connect(testMode = false, autoloadModels = true, noLog = false) {
const acquireConnectionTimeout = 120 * 1000;
const Dialect = require("knex/lib/dialects/sqlite3/index.js");
@@ -109,18 +115,33 @@ class Database {
// Auto map the model to a bean object
R.freeze(true);
await R.autoloadModels("./server/model");
if (autoloadModels) {
await R.autoloadModels("./server/model");
}
await R.exec("PRAGMA foreign_keys = ON");
// Change to WAL
await R.exec("PRAGMA journal_mode = WAL");
if (testMode) {
// Change to MEMORY
await R.exec("PRAGMA journal_mode = MEMORY");
} else {
// Change to WAL
await R.exec("PRAGMA journal_mode = WAL");
}
await R.exec("PRAGMA cache_size = -12000");
await R.exec("PRAGMA auto_vacuum = FULL");
console.log("SQLite config:");
console.log(await R.getAll("PRAGMA journal_mode"));
console.log(await R.getAll("PRAGMA cache_size"));
console.log("SQLite Version: " + await R.getCell("SELECT sqlite_version()"));
// This ensures that an operating system crash or power failure will not corrupt the database.
// FULL synchronous is very safe, but it is also slower.
// Read more: https://sqlite.org/pragma.html#pragma_synchronous
await R.exec("PRAGMA synchronous = FULL");
if (!noLog) {
log.info("db", "SQLite config:");
log.info("db", await R.getAll("PRAGMA journal_mode"));
log.info("db", await R.getAll("PRAGMA cache_size"));
log.info("db", "SQLite Version: " + await R.getCell("SELECT sqlite_version()"));
}
}
static async patch() {
@@ -130,15 +151,15 @@ class Database {
version = 0;
}
console.info("Your database version: " + version);
console.info("Latest database version: " + this.latestVersion);
log.info("db", "Your database version: " + version);
log.info("db", "Latest database version: " + this.latestVersion);
if (version === this.latestVersion) {
console.info("Database patch not needed");
log.info("db", "Database patch not needed");
} else if (version > this.latestVersion) {
console.info("Warning: Database version is newer than expected");
log.info("db", "Warning: Database version is newer than expected");
} else {
console.info("Database patch is needed");
log.info("db", "Database patch is needed");
this.backup(version);
@@ -146,17 +167,17 @@ class Database {
try {
for (let i = version + 1; i <= this.latestVersion; i++) {
const sqlFile = `./db/patch${i}.sql`;
console.info(`Patching ${sqlFile}`);
log.info("db", `Patching ${sqlFile}`);
await Database.importSQLFile(sqlFile);
console.info(`Patched ${sqlFile}`);
log.info("db", `Patched ${sqlFile}`);
await setSetting("database_version", i);
}
} catch (ex) {
await Database.close();
console.error(ex);
console.error("Start Uptime-Kuma failed due to issue patching the database");
console.error("Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
log.error("db", ex);
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
log.error("db", "Please submit a bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
this.restore();
process.exit(1);
@@ -164,6 +185,7 @@ class Database {
}
await this.patch2();
await this.migrateNewStatusPage();
}
/**
@@ -171,15 +193,15 @@ class Database {
* @returns {Promise<void>}
*/
static async patch2() {
console.log("Database Patch 2.0 Process");
log.info("db", "Database Patch 2.0 Process");
let databasePatchedFiles = await setting("databasePatchedFiles");
if (! databasePatchedFiles) {
databasePatchedFiles = {};
}
debug("Patched files:");
debug(databasePatchedFiles);
log.debug("db", "Patched files:");
log.debug("db", databasePatchedFiles);
try {
for (let sqlFilename in this.patchList) {
@@ -187,15 +209,15 @@ class Database {
}
if (this.patched) {
console.log("Database Patched Successfully");
log.info("db", "Database Patched Successfully");
}
} catch (ex) {
await Database.close();
console.error(ex);
console.error("Start Uptime-Kuma failed due to issue patching the database");
console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
log.error("db", ex);
log.error("db", "Start Uptime-Kuma failed due to issue patching the database");
log.error("db", "Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues");
this.restore();
@@ -205,6 +227,74 @@ class Database {
await setSetting("databasePatchedFiles", databasePatchedFiles);
}
/**
* Migrate status page value in setting to "status_page" table
* @returns {Promise<void>}
*/
static async migrateNewStatusPage() {
// Fix 1.13.0 empty slug bug
await R.exec("UPDATE status_page SET slug = 'empty-slug-recover' WHERE TRIM(slug) = ''");
let title = await setting("title");
if (title) {
console.log("Migrating Status Page");
let statusPageCheck = await R.findOne("status_page", " slug = 'default' ");
if (statusPageCheck !== null) {
console.log("Migrating Status Page - Skip, default slug record is already existing");
return;
}
let statusPage = R.dispense("status_page");
statusPage.slug = "default";
statusPage.title = title;
statusPage.description = await setting("description");
statusPage.icon = await setting("icon");
statusPage.theme = await setting("statusPageTheme");
statusPage.published = !!await setting("statusPagePublished");
statusPage.search_engine_index = !!await setting("searchEngineIndex");
statusPage.show_tags = !!await setting("statusPageTags");
statusPage.password = null;
if (!statusPage.title) {
statusPage.title = "My Status Page";
}
if (!statusPage.icon) {
statusPage.icon = "";
}
if (!statusPage.theme) {
statusPage.theme = "light";
}
let id = await R.store(statusPage);
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [
id
]);
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [
id
]);
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
// Migrate Entry Page if it is status page
let entryPage = await setting("entryPage");
if (entryPage === "statusPage") {
await setSetting("entryPage", "statusPage-default", "general");
}
console.log("Migrating Status Page - Done");
}
}
/**
* Used it patch2() only
* @param sqlFilename
@@ -214,16 +304,16 @@ class Database {
let value = this.patchList[sqlFilename];
if (! value) {
console.log(sqlFilename + " skip");
log.info("db", sqlFilename + " skip");
return;
}
// Check if patched
if (! databasePatchedFiles[sqlFilename]) {
console.log(sqlFilename + " is not patched");
log.info("db", sqlFilename + " is not patched");
if (value.parents) {
console.log(sqlFilename + " need parents");
log.info("db", sqlFilename + " need parents");
for (let parentSQLFilename of value.parents) {
await this.patch2Recursion(parentSQLFilename, databasePatchedFiles);
}
@@ -231,14 +321,14 @@ class Database {
this.backup(dayjs().format("YYYYMMDDHHmmss"));
console.log(sqlFilename + " is patching");
log.info("db", sqlFilename + " is patching");
this.patched = true;
await this.importSQLFile("./db/" + sqlFilename);
databasePatchedFiles[sqlFilename] = true;
console.log(sqlFilename + " was patched successfully");
log.info("db", sqlFilename + " was patched successfully");
} else {
debug(sqlFilename + " is already patched, skip");
log.debug("db", sqlFilename + " is already patched, skip");
}
}
@@ -290,7 +380,7 @@ class Database {
};
process.addListener("unhandledRejection", listener);
console.log("Closing the database");
log.info("db", "Closing the database");
while (true) {
Database.noReject = true;
@@ -300,10 +390,10 @@ class Database {
if (Database.noReject) {
break;
} else {
console.log("Waiting to close the database");
log.info("db", "Waiting to close the database");
}
}
console.log("SQLite closed");
log.info("db", "SQLite closed");
process.removeListener("unhandledRejection", listener);
}
@@ -315,7 +405,7 @@ class Database {
*/
static backup(version) {
if (! this.backupPath) {
console.info("Backing up the database");
log.info("db", "Backing up the database");
this.backupPath = this.dataDir + "kuma.db.bak" + version;
fs.copyFileSync(Database.path, this.backupPath);
@@ -338,7 +428,7 @@ class Database {
*/
static restore() {
if (this.backupPath) {
console.error("Patching the database failed!!! Restoring the backup");
log.error("db", "Patching the database failed!!! Restoring the backup");
const shmPath = Database.path + "-shm";
const walPath = Database.path + "-wal";
@@ -357,7 +447,7 @@ class Database {
fs.unlinkSync(walPath);
}
} catch (e) {
console.log("Restore failed; you may need to restore the backup manually");
log.error("db", "Restore failed; you may need to restore the backup manually");
process.exit(1);
}
@@ -373,14 +463,14 @@ class Database {
}
} else {
console.log("Nothing to restore");
log.info("db", "Nothing to restore");
}
}
static getSize() {
debug("Database.getSize()");
log.debug("db", "Database.getSize()");
let stats = fs.statSync(Database.path);
debug(stats);
log.debug("db", stats);
return stats.size;
}

View File

@@ -3,12 +3,19 @@
Modified with 0 dependencies
*/
let fs = require("fs");
const { log } = require("../src/util");
let ImageDataURI = (() => {
/**
* @param {string} dataURI - A string that is a valid Data URI.
* @returns {?Object} An object with properties "imageType" and "dataBase64". The former is the image type, e.g., "png", and the latter is a base64 encoded string of the image's binary data. If it fails to parse, returns null instead of an object.
*
* Generated by Trelent
*/
function decode(dataURI) {
if (!/data:image\//.test(dataURI)) {
console.log("ImageDataURI :: Error :: It seems that it is not an Image Data URI. Couldn't match \"data:image/\"");
log.error("image-data-uri", "It seems that it is not an Image Data URI. Couldn't match \"data:image/\"");
return null;
}
@@ -20,9 +27,16 @@ let ImageDataURI = (() => {
};
}
/**
* @param {Buffer} data - The image data to be encoded.
* @param {String} mediaType - The type of the image, e.g., "image/png".
* @returns {String|null} A string representing the base64-encoded version of the given Buffer object or null if an error occurred.
*
* Generated by Trelent
*/
function encode(data, mediaType) {
if (!data || !mediaType) {
console.log("ImageDataURI :: Error :: Missing some of the required params: data, mediaType ");
log.error("image-data-uri", "Missing some of the required params: data, mediaType");
return null;
}
@@ -33,6 +47,13 @@ let ImageDataURI = (() => {
return dataImgBase64;
}
/**
* Converts a data URI to a file path.
* @param {string} dataURI The Data URI of the image.
* @param {string} [filePath] The path where the image will be saved, defaults to "./".
*
* Generated by Trelent
*/
function outputFile(dataURI, filePath) {
filePath = filePath || "./";
return new Promise((resolve, reject) => {

View File

@@ -1,7 +1,8 @@
const path = require("path");
const Bree = require("bree");
const { SHARE_ENV } = require("worker_threads");
const { log } = require("../src/util");
let bree;
const jobs = [
{
name: "clear-old-data",
@@ -10,7 +11,7 @@ const jobs = [
];
const initBackgroundJobs = function (args) {
const bree = new Bree({
bree = new Bree({
root: path.resolve("server", "jobs"),
jobs,
worker: {
@@ -18,7 +19,7 @@ const initBackgroundJobs = function (args) {
workerData: args,
},
workerMessageHandler: (message) => {
console.log("[Background Job]:", message);
log.info("jobs", message);
}
});
@@ -26,6 +27,13 @@ const initBackgroundJobs = function (args) {
return bree;
};
module.exports = {
initBackgroundJobs
const stopBackgroundJobs = function () {
if (bree) {
bree.stop();
}
};
module.exports = {
initBackgroundJobs,
stopBackgroundJobs
};

View File

@@ -30,7 +30,7 @@ const DEFAULT_KEEP_PERIOD = 180;
try {
await R.exec(
"DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ",
[parsedPeriod]
[ parsedPeriod ]
);
} catch (e) {
log(`Failed to clear old data: ${e.message}`);

View File

@@ -9,7 +9,7 @@ const log = function (any) {
};
const exit = function (error) {
if (error && error != 0) {
if (error && error !== 0) {
process.exit(error);
} else {
if (parentPort) {

View File

@@ -3,12 +3,12 @@ const { R } = require("redbean-node");
class Group extends BeanModel {
async toPublicJSON() {
async toPublicJSON(showTags = false) {
let monitorBeanList = await this.getMonitorList();
let monitorList = [];
for (let bean of monitorBeanList) {
monitorList.push(await bean.toPublicJSON());
monitorList.push(await bean.toPublicJSON(showTags));
}
return {

View File

@@ -6,11 +6,12 @@ dayjs.extend(utc);
dayjs.extend(timezone);
const axios = require("axios");
const { Prometheus } = require("../prometheus");
const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog } = require("../util-server");
const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog, mqttAsync } = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
const { Notification } = require("../notification");
const { Proxy } = require("../proxy");
const { demoMode } = require("../config");
const version = require("../../package.json").version;
const apicache = require("../modules/apicache");
@@ -24,20 +25,24 @@ const apicache = require("../modules/apicache");
class Monitor extends BeanModel {
/**
* Return a object that ready to parse to JSON for public
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
*/
async toPublicJSON() {
return {
async toPublicJSON(showTags = false) {
let obj = {
id: this.id,
name: this.name,
};
if (showTags) {
obj.tags = await this.getTags();
}
return obj;
}
/**
* Return a object that ready to parse to JSON
* Return an object that ready to parse to JSON
*/
async toJSON() {
async toJSON(includeSensitiveData = true) {
let notificationIDList = {};
@@ -49,15 +54,13 @@ class Monitor extends BeanModel {
notificationIDList[bean.notification_id] = true;
}
const tags = await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
const tags = await this.getTags();
return {
let data = {
id: this.id,
name: this.name,
url: this.url,
method: this.method,
body: this.body,
headers: this.headers,
hostname: this.hostname,
port: this.port,
maxretries: this.maxretries,
@@ -67,6 +70,7 @@ class Monitor extends BeanModel {
interval: this.interval,
retryInterval: this.retryInterval,
keyword: this.keyword,
expiryNotification: this.isEnabledExpiryNotification(),
ignoreTls: this.getIgnoreTls(),
upsideDown: this.isUpsideDown(),
maxredirects: this.maxredirects,
@@ -74,10 +78,44 @@ 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,
proxyId: this.proxy_id,
notificationIDList,
tags: tags,
mqttUsername: this.mqttUsername,
mqttPassword: this.mqttPassword,
mqttTopic: this.mqttTopic,
mqttSuccessMessage: this.mqttSuccessMessage
};
if (includeSensitiveData) {
data = {
...data,
headers: this.headers,
body: this.body,
basic_auth_user: this.basic_auth_user,
basic_auth_pass: this.basic_auth_pass,
pushToken: this.pushToken,
};
}
return data;
}
async getTags() {
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [ this.id ]);
}
/**
* Encode user and password to Base64 encoding
* for HTTP "basic" auth, as per RFC-7617
* @returns {string}
*/
encodeBase64(user, pass) {
return Buffer.from(user + ":" + pass).toString("base64");
}
isEnabledExpiryNotification() {
return Boolean(this.expiryNotification);
}
/**
@@ -108,11 +146,24 @@ class Monitor extends BeanModel {
const beat = async () => {
let beatInterval = this.interval;
if (! beatInterval) {
beatInterval = 1;
}
if (demoMode) {
if (beatInterval < 20) {
console.log("beat interval too low, reset to 20s");
beatInterval = 20;
}
}
// Expose here for prometheus update
// undefined if not https
let tlsInfo = undefined;
if (! previousBeat) {
if (!previousBeat) {
previousBeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [
this.id,
]);
@@ -130,7 +181,7 @@ class Monitor extends BeanModel {
}
// Duration
if (! isFirstBeat) {
if (!isFirstBeat) {
bean.duration = dayjs(bean.time).diff(dayjs(previousBeat.time), "second");
} else {
bean.duration = 0;
@@ -141,28 +192,59 @@ class Monitor extends BeanModel {
// Do not do any queries/high loading things before the "bean.ping"
let startTime = dayjs().valueOf();
debug(`[${this.name}] Prepare Options for axios`);
// HTTP basic auth
let basicAuthHeader = {};
if (this.basic_auth_user) {
basicAuthHeader = {
"Authorization": "Basic " + this.encodeBase64(this.basic_auth_user, this.basic_auth_pass),
};
}
const httpsAgentOptions = {
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: !this.getIgnoreTls(),
};
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
const options = {
url: this.url,
method: (this.method || "get").toLowerCase(),
...(this.body ? { data: JSON.parse(this.body) } : {}),
timeout: this.interval * 1000 * 0.8,
headers: {
"Accept": "*/*",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"User-Agent": "Uptime-Kuma/" + version,
...(this.headers ? JSON.parse(this.headers) : {}),
...(basicAuthHeader),
},
httpsAgent: new https.Agent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: ! this.getIgnoreTls(),
}),
maxRedirects: this.maxredirects,
validateStatus: (status) => {
return checkStatusCode(status, this.getAcceptedStatuscodes());
},
};
debug(`[${this.name}] Axios Request`);
if (this.proxy_id) {
const proxy = await R.load("proxy", this.proxy_id);
if (proxy && proxy.active) {
const { httpAgent, httpsAgent } = Proxy.createAgents(proxy, {
httpsAgentOptions: httpsAgentOptions,
});
options.proxy = false;
options.httpAgent = httpAgent;
options.httpsAgent = httpsAgent;
}
}
if (!options.httpsAgent) {
options.httpsAgent = new https.Agent(httpsAgentOptions);
}
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
log.debug("monitor", `[${this.name}] Axios Request`);
let res = await axios.request(options);
bean.msg = `${res.status} - ${res.statusText}`;
bean.ping = dayjs().valueOf() - startTime;
@@ -170,29 +252,30 @@ class Monitor extends BeanModel {
// Check certificate if https is used
let certInfoStartTime = dayjs().valueOf();
if (this.getUrl()?.protocol === "https:") {
debug(`[${this.name}] Check cert`);
log.debug("monitor", `[${this.name}] Check cert`);
try {
let tlsInfoObject = checkCertificate(res);
tlsInfo = await this.updateTlsInfo(tlsInfoObject);
if (!this.getIgnoreTls()) {
debug(`[${this.name}] call sendCertNotification`);
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) {
log.debug("monitor", `[${this.name}] call sendCertNotification`);
await this.sendCertNotification(tlsInfoObject);
}
} catch (e) {
if (e.message !== "No TLS certificate in response") {
console.error(e.message);
log.error("monitor", "Caught error");
log.error("monitor", e.message);
}
}
}
if (process.env.TIMELOGGER === "1") {
debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
}
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) {
console.log(res.data);
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) {
log.info("monitor", res.data);
}
if (this.type === "http") {
@@ -231,24 +314,24 @@ class Monitor extends BeanModel {
let dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.dns_resolve_type);
bean.ping = dayjs().valueOf() - startTime;
if (this.dns_resolve_type == "A" || this.dns_resolve_type == "AAAA" || this.dns_resolve_type == "TXT") {
if (this.dns_resolve_type === "A" || this.dns_resolve_type === "AAAA" || this.dns_resolve_type === "TXT") {
dnsMessage += "Records: ";
dnsMessage += dnsRes.join(" | ");
} else if (this.dns_resolve_type == "CNAME" || this.dns_resolve_type == "PTR") {
} else if (this.dns_resolve_type === "CNAME" || this.dns_resolve_type === "PTR") {
dnsMessage = dnsRes[0];
} else if (this.dns_resolve_type == "CAA") {
} else if (this.dns_resolve_type === "CAA") {
dnsMessage = dnsRes[0].issue;
} else if (this.dns_resolve_type == "MX") {
} else if (this.dns_resolve_type === "MX") {
dnsRes.forEach(record => {
dnsMessage += `Hostname: ${record.exchange} - Priority: ${record.priority} | `;
});
dnsMessage = dnsMessage.slice(0, -2);
} else if (this.dns_resolve_type == "NS") {
} else if (this.dns_resolve_type === "NS") {
dnsMessage += "Servers: ";
dnsMessage += dnsRes.join(" | ");
} else if (this.dns_resolve_type == "SOA") {
} else if (this.dns_resolve_type === "SOA") {
dnsMessage += `NS-Name: ${dnsRes.nsname} | Hostmaster: ${dnsRes.hostmaster} | Serial: ${dnsRes.serial} | Refresh: ${dnsRes.refresh} | Retry: ${dnsRes.retry} | Expire: ${dnsRes.expire} | MinTTL: ${dnsRes.minttl}`;
} else if (this.dns_resolve_type == "SRV") {
} else if (this.dns_resolve_type === "SRV") {
dnsRes.forEach(record => {
dnsMessage += `Name: ${record.name} | Port: ${record.port} | Priority: ${record.priority} | Weight: ${record.weight} | `;
});
@@ -272,14 +355,17 @@ class Monitor extends BeanModel {
time
]);
debug("heartbeatCount" + heartbeatCount + " " + time);
log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time);
if (heartbeatCount <= 0) {
// Fix #922, since previous heartbeat could be inserted by api, it should get from database
previousBeat = await Monitor.getPreviousHeartbeat(this.id);
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);
this.heartbeatInterval = setTimeout(beat, beatInterval * 1000);
return;
}
@@ -300,7 +386,7 @@ class Monitor extends BeanModel {
},
httpsAgent: new https.Agent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: ! this.getIgnoreTls(),
rejectUnauthorized: !this.getIgnoreTls(),
}),
maxRedirects: this.maxredirects,
validateStatus: (status) => {
@@ -322,7 +408,14 @@ class Monitor extends BeanModel {
} else {
throw new Error("Server not found on Steam");
}
} else if (this.type === "mqtt") {
bean.msg = await mqttAsync(this.hostname, this.mqttTopic, this.mqttSuccessMessage, {
port: this.port,
username: this.mqttUsername,
password: this.mqttPassword,
interval: this.interval,
});
bean.status = UP;
} else {
bean.msg = "Unknown Monitor Type";
bean.status = PENDING;
@@ -353,9 +446,7 @@ class Monitor extends BeanModel {
}
}
let beatInterval = this.interval;
debug(`[${this.name}] Check isImportant`);
log.debug("monitor", `[${this.name}] Check isImportant`);
let isImportant = Monitor.isImportantBeat(isFirstBeat, previousBeat?.status, bean.status);
// Mark as important if status changed, ignore pending pings,
@@ -363,11 +454,11 @@ class Monitor extends BeanModel {
if (isImportant) {
bean.important = true;
debug(`[${this.name}] sendNotification`);
log.debug("monitor", `[${this.name}] sendNotification`);
await Monitor.sendNotification(isFirstBeat, this, bean);
// Clear Status Page Cache
debug(`[${this.name}] apicache clear`);
log.debug("monitor", `[${this.name}] apicache clear`);
apicache.clear();
} else {
@@ -375,41 +466,33 @@ class Monitor extends BeanModel {
}
if (bean.status === UP) {
console.info(`Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`);
log.info("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`);
} else if (bean.status === PENDING) {
if (this.retryInterval > 0) {
beatInterval = this.retryInterval;
}
console.warn(`Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`);
log.warn("monitor", `Monitor #${this.id} '${this.name}': Pending: ${bean.msg} | Max retries: ${this.maxretries} | Retry: ${retries} | Retry Interval: ${beatInterval} seconds | Type: ${this.type}`);
} else {
console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
log.warn("monitor", `Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Interval: ${beatInterval} seconds | Type: ${this.type}`);
}
debug(`[${this.name}] Send to socket`);
log.debug("monitor", `[${this.name}] Send to socket`);
io.to(this.user_id).emit("heartbeat", bean.toJSON());
Monitor.sendStats(io, this.id, this.user_id);
debug(`[${this.name}] Store`);
log.debug("monitor", `[${this.name}] Store`);
await R.store(bean);
debug(`[${this.name}] prometheus.update`);
log.debug("monitor", `[${this.name}] prometheus.update`);
prometheus.update(bean, tlsInfo);
previousBeat = bean;
if (! this.isStop) {
if (demoMode) {
if (beatInterval < 20) {
console.log("beat interval too low, reset to 20s");
beatInterval = 20;
}
}
debug(`[${this.name}] SetTimeout for next check.`);
log.debug("monitor", `[${this.name}] SetTimeout for next check.`);
this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000);
} else {
console.log(`[${this.name}] isStop = true, no next check.`);
log.info("monitor", `[${this.name}] isStop = true, no next check.`);
}
};
@@ -420,10 +503,10 @@ class Monitor extends BeanModel {
} catch (e) {
console.trace(e);
errorLog(e, false);
console.error("Please report to https://github.com/louislam/uptime-kuma/issues");
log.error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues");
if (! this.isStop) {
console.log("Try to restart the monitor");
log.info("monitor", "Try to restart the monitor");
this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000);
}
}
@@ -442,6 +525,12 @@ class Monitor extends BeanModel {
stop() {
clearTimeout(this.heartbeatInterval);
this.isStop = true;
this.prometheus().remove();
}
prometheus() {
return new Prometheus(this);
}
/**
@@ -464,41 +553,41 @@ class Monitor extends BeanModel {
* @returns {Promise<object>}
*/
async updateTlsInfo(checkCertificateResult) {
let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
let tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
this.id,
]);
if (tls_info_bean == null) {
tls_info_bean = R.dispense("monitor_tls_info");
tls_info_bean.monitor_id = this.id;
if (tlsInfoBean == null) {
tlsInfoBean = R.dispense("monitor_tls_info");
tlsInfoBean.monitor_id = this.id;
} else {
// Clear sent history if the cert changed.
try {
let oldCertInfo = JSON.parse(tls_info_bean.info_json);
let oldCertInfo = JSON.parse(tlsInfoBean.info_json);
let isValidObjects = oldCertInfo && oldCertInfo.certInfo && checkCertificateResult && checkCertificateResult.certInfo;
if (isValidObjects) {
if (oldCertInfo.certInfo.fingerprint256 !== checkCertificateResult.certInfo.fingerprint256) {
debug("Resetting sent_history");
log.debug("monitor", "Resetting sent_history");
await R.exec("DELETE FROM notification_sent_history WHERE type = 'certificate' AND monitor_id = ?", [
this.id
]);
} else {
debug("No need to reset sent_history");
debug(oldCertInfo.certInfo.fingerprint256);
debug(checkCertificateResult.certInfo.fingerprint256);
log.debug("monitor", "No need to reset sent_history");
log.debug("monitor", oldCertInfo.certInfo.fingerprint256);
log.debug("monitor", checkCertificateResult.certInfo.fingerprint256);
}
} else {
debug("Not valid object");
log.debug("monitor", "Not valid object");
}
} catch (e) { }
}
tls_info_bean.info_json = JSON.stringify(checkCertificateResult);
await R.store(tls_info_bean);
tlsInfoBean.info_json = JSON.stringify(checkCertificateResult);
await R.store(tlsInfoBean);
return checkCertificateResult;
}
@@ -512,7 +601,7 @@ class Monitor extends BeanModel {
await Monitor.sendUptime(24 * 30, io, monitorID, userID);
await Monitor.sendCertInfo(io, monitorID, userID);
} else {
debug("No clients in the room, no need to send stats");
log.debug("monitor", "No clients in the room, no need to send stats");
}
}
@@ -539,11 +628,11 @@ class Monitor extends BeanModel {
}
static async sendCertInfo(io, monitorID, userID) {
let tls_info = await R.findOne("monitor_tls_info", "monitor_id = ?", [
let tlsInfo = await R.findOne("monitor_tls_info", "monitor_id = ?", [
monitorID,
]);
if (tls_info != null) {
io.to(userID).emit("certInfo", monitorID, tls_info.info_json);
if (tlsInfo != null) {
io.to(userID).emit("certInfo", monitorID, tlsInfo.info_json);
}
}
@@ -605,7 +694,7 @@ class Monitor extends BeanModel {
} else {
// Handle new monitor with only one beat, because the beat's duration = 0
let status = parseInt(await R.getCell("SELECT `status` FROM heartbeat WHERE monitor_id = ?", [ monitorID ]));
let status = parseInt(await R.getCell("SELECT `status` FROM heartbeat WHERE monitor_id = ?", [monitorID]));
if (status === UP) {
uptime = 1;
@@ -657,10 +746,10 @@ class Monitor extends BeanModel {
for (let notification of notificationList) {
try {
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON());
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), bean.toJSON());
} catch (e) {
console.error("Cannot send notification to " + notification.name);
console.log(e);
log.error("monitor", "Cannot send notification to " + notification.name);
log.error("monitor", e);
}
}
}
@@ -677,7 +766,7 @@ class Monitor extends BeanModel {
if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) {
const notificationList = await Monitor.getNotificationList(this);
debug("call sendCertNotificationByTargetDays");
log.debug("monitor", "call sendCertNotificationByTargetDays");
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 21, notificationList);
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 14, notificationList);
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, 7, notificationList);
@@ -687,7 +776,7 @@ class Monitor extends BeanModel {
async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) {
if (daysRemaining > targetDays) {
debug(`No need to send cert notification. ${daysRemaining} > ${targetDays}`);
log.debug("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`);
return;
}
@@ -701,21 +790,21 @@ class Monitor extends BeanModel {
// Sent already, no need to send again
if (row) {
debug("Sent already, no need to send again");
log.debug("monitor", "Sent already, no need to send again");
return;
}
let sent = false;
debug("Send certificate notification");
log.debug("monitor", "Send certificate notification");
for (let notification of notificationList) {
try {
debug("Sending to " + notification.name);
log.debug("monitor", "Sending to " + notification.name);
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] Certificate will be expired in ${daysRemaining} days`);
sent = true;
} catch (e) {
console.error("Cannot send cert notification to " + notification.name);
console.error(e);
log.error("monitor", "Cannot send cert notification to " + notification.name);
log.error("monitor", e);
}
}
@@ -727,9 +816,18 @@ class Monitor extends BeanModel {
]);
}
} else {
debug("No notification, no need to send cert notification");
log.debug("monitor", "No notification, no need to send cert notification");
}
}
static async getPreviousHeartbeat(monitorID) {
return await R.getRow(`
SELECT status, time FROM heartbeat
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
`, [
monitorID
]);
}
}
module.exports = Monitor;

21
server/model/proxy.js Normal file
View File

@@ -0,0 +1,21 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
class Proxy extends BeanModel {
toJSON() {
return {
id: this._id,
userId: this._user_id,
protocol: this._protocol,
host: this._host,
port: this._port,
auth: !!this._auth,
username: this._username,
password: this._password,
active: !!this._active,
default: !!this._default,
createdDate: this._created_date,
};
}
}
module.exports = Proxy;

132
server/model/status_page.js Normal file
View File

@@ -0,0 +1,132 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const { R } = require("redbean-node");
class StatusPage extends BeanModel {
static domainMappingList = { };
/**
* Return object like this: { "test-uptime.kuma.pet": "default" }
* @returns {Promise<void>}
*/
static async loadDomainMappingList() {
StatusPage.domainMappingList = await R.getAssoc(`
SELECT domain, slug
FROM status_page, status_page_cname
WHERE status_page.id = status_page_cname.status_page_id
`);
}
static async sendStatusPageList(io, socket) {
let result = {};
let list = await R.findAll("status_page", " ORDER BY title ");
for (let item of list) {
result[item.id] = await item.toJSON();
}
io.to(socket.userID).emit("statusPageList", result);
return list;
}
async updateDomainNameList(domainNameList) {
if (!Array.isArray(domainNameList)) {
throw new Error("Invalid array");
}
let trx = await R.begin();
await trx.exec("DELETE FROM status_page_cname WHERE status_page_id = ?", [
this.id,
]);
try {
for (let domain of domainNameList) {
if (typeof domain !== "string") {
throw new Error("Invalid domain");
}
if (domain.trim() === "") {
continue;
}
// If the domain name is used in another status page, delete it
await trx.exec("DELETE FROM status_page_cname WHERE domain = ?", [
domain,
]);
let mapping = trx.dispense("status_page_cname");
mapping.status_page_id = this.id;
mapping.domain = domain;
await trx.store(mapping);
}
await trx.commit();
} catch (error) {
await trx.rollback();
throw error;
}
}
getDomainNameList() {
let domainList = [];
for (let domain in StatusPage.domainMappingList) {
let s = StatusPage.domainMappingList[domain];
if (this.slug === s) {
domainList.push(domain);
}
}
return domainList;
}
async toJSON() {
return {
id: this.id,
slug: this.slug,
title: this.title,
description: this.description,
icon: this.getIcon(),
theme: this.theme,
published: !!this.published,
showTags: !!this.show_tags,
domainNameList: this.getDomainNameList(),
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
};
}
async toPublicJSON() {
return {
slug: this.slug,
title: this.title,
description: this.description,
icon: this.getIcon(),
theme: this.theme,
published: !!this.published,
showTags: !!this.show_tags,
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
};
}
static async slugToID(slug) {
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
slug
]);
}
getIcon() {
if (!this.icon) {
return "/icon.svg";
} else {
return this.icon;
}
}
}
module.exports = StatusPage;

View File

@@ -5,17 +5,29 @@ const { R } = require("redbean-node");
class User extends BeanModel {
/**
* Direct execute, no need R.store()
*
* Fix #1510, as in the context reset-password.js, there is no auto model mapping. Call this static function instead.
* @param userID
* @param newPassword
* @returns {Promise<void>}
*/
static async resetPassword(userID, newPassword) {
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
passwordHash.generate(newPassword),
userID
]);
}
/**
*
* @param newPassword
* @returns {Promise<void>}
*/
async resetPassword(newPassword) {
await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [
passwordHash.generate(newPassword),
this.id
]);
await User.resetPassword(this.id, newPassword);
this.password = newPassword;
}
}
module.exports = User;

View File

@@ -68,6 +68,15 @@ function ApiCache() {
instances.push(this);
this.id = instances.length;
/**
* Logs a message to the console if the `DEBUG` environment variable is set.
* @param {string} a - The first argument to log.
* @param {string} b - The second argument to log.
* @param {string} c - The third argument to log.
* @param {string} d - The fourth argument to log, and so on... (optional)
*
* Generated by Trelent
*/
function debug(a, b, c, d) {
let arr = ["\x1b[36m[apicache]\x1b[0m", a, b, c, d].filter(function (arg) {
return arg !== undefined;
@@ -77,6 +86,13 @@ function ApiCache() {
return (globalOptions.debug || debugEnv) && console.log.apply(null, arr);
}
/**
* Returns true if the given request and response should be logged.
* @param {Object} request The HTTP request object.
* @param {Object} response The HTTP response object.
*
* Generated by Trelent
*/
function shouldCacheResponse(request, response, toggle) {
let opt = globalOptions;
let codes = opt.statusCodes;
@@ -99,6 +115,12 @@ function ApiCache() {
return true;
}
/**
* Adds a key to the index.
* @param {string} key The key to add.
*
* Generated by Trelent
*/
function addIndexEntries(key, req) {
let groupName = req.apicacheGroup;
@@ -111,6 +133,13 @@ function ApiCache() {
index.all.unshift(key);
}
/**
* Returns a new object containing only the whitelisted headers.
* @param {Object} headers The original object of header names and values.
* @param {Array.<string>} globalOptions.headerWhitelist An array of strings representing the whitelisted header names to keep in the output object.
*
* Generated by Trelent
*/
function filterBlacklistedHeaders(headers) {
return Object.keys(headers)
.filter(function (key) {
@@ -122,6 +151,12 @@ function ApiCache() {
}, {});
}
/**
* @param {Object} headers The response headers to filter.
* @returns {Object} A new object containing only the whitelisted response headers.
*
* Generated by Trelent
*/
function createCacheObject(status, headers, data, encoding) {
return {
status: status,
@@ -132,6 +167,14 @@ function ApiCache() {
};
}
/**
* Sets a cache value for the given key.
* @param {string} key The cache key to set.
* @param {*} value The cache value to set.
* @param {number} duration How long in milliseconds the cached response should be valid for (defaults to 1 hour).
*
* Generated by Trelent
*/
function cacheResponse(key, value, duration) {
let redis = globalOptions.redisClient;
let expireCallback = globalOptions.events.expire;
@@ -154,6 +197,12 @@ function ApiCache() {
}, Math.min(duration, 2147483647));
}
/**
* Appends content to the response.
* @param {string|Buffer} content The content to append.
*
* Generated by Trelent
*/
function accumulateContent(res, content) {
if (content) {
if (typeof content == "string") {
@@ -179,6 +228,13 @@ function ApiCache() {
}
}
/**
* Monkeypatches the response object to add cache control headers and create a cache object.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
*
* Generated by Trelent
*/
function makeResponseCacheable(req, res, next, key, duration, strDuration, toggle) {
// monkeypatch res.end to create cache object
res._apicache = {
@@ -245,6 +301,13 @@ function ApiCache() {
next();
}
/**
* @param {Request} request
* @param {Response} response
* @returns {boolean|undefined} true if the request should be cached, false otherwise. If undefined, defaults to true.
*
* Generated by Trelent
*/
function sendCachedResponse(request, response, cacheObject, toggle, next, duration) {
if (toggle && !toggle(request, response)) {
return next();
@@ -365,6 +428,13 @@ function ApiCache() {
return this.getIndex();
};
/**
* Converts a duration string to an integer number of milliseconds.
* @param {string} duration - The string to convert.
* @returns {number} The converted value in milliseconds, or the defaultDuration if it can't be parsed.
*
* Generated by Trelent
*/
function parseDuration(duration, defaultDuration) {
if (typeof duration === "number") {
return duration;

View File

@@ -0,0 +1,67 @@
const NotificationProvider = require("./notification-provider");
const { DOWN, UP } = require("../../src/util");
const axios = require("axios");
class Alerta extends NotificationProvider {
name = "alerta";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let alertaUrl = `${notification.alertaApiEndpoint}`;
let config = {
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Authorization": "Key " + notification.alertaApiKey,
}
};
let data = {
environment: notification.alertaEnvironment,
severity: "critical",
correlate: [],
service: [ "UptimeKuma" ],
value: "Timeout",
tags: [ "uptimekuma" ],
attributes: {},
origin: "uptimekuma",
type: "exceptionAlert",
};
if (heartbeatJSON == null) {
let postData = Object.assign({
event: "msg",
text: msg,
group: "uptimekuma-msg",
resource: "Message",
}, data);
await axios.post(alertaUrl, postData, config);
} else {
let datadup = Object.assign( {
correlate: [ "service_up", "service_down" ],
event: monitorJSON["type"],
group: "uptimekuma-" + monitorJSON["type"],
resource: monitorJSON["name"],
}, data );
if (heartbeatJSON["status"] === DOWN) {
datadup.severity = notification.alertaAlertState; // critical
datadup.text = "Service " + monitorJSON["type"] + " is down.";
await axios.post(alertaUrl, datadup, config);
} else if (heartbeatJSON["status"] === UP) {
datadup.severity = notification.alertaRecoverState; // cleaned
datadup.text = "Service " + monitorJSON["type"] + " is up.";
await axios.post(alertaUrl, datadup, config);
}
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Alerta;

View File

@@ -64,7 +64,7 @@ class AliyunSMS extends NotificationProvider {
};
let result = await axios(config);
if (result.data.Message == "OK") {
if (result.data.Message === "OK") {
return true;
}
return false;

View File

@@ -1,12 +1,12 @@
const NotificationProvider = require("./notification-provider");
const child_process = require("child_process");
const childProcess = require("child_process");
class Apprise extends NotificationProvider {
name = "apprise";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
let s = childProcess.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL ]);
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
@@ -16,7 +16,7 @@ class Apprise extends NotificationProvider {
return "Sent Successfully";
}
throw new Error(output)
throw new Error(output);
} else {
return "No output from apprise";
}

View File

@@ -21,31 +21,26 @@ class Bark extends NotificationProvider {
name = "Bark";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
var barkEndpoint = notification.barkEndpoint;
let barkEndpoint = notification.barkEndpoint;
// check if the endpoint has a "/" suffix, if so, delete it first
if (barkEndpoint.endsWith("/")) {
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
}
// check if the endpoint has a "/" suffix, if so, delete it first
if (barkEndpoint.endsWith("/")) {
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
}
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) {
let title = "UptimeKuma Monitor Up";
return await this.postNotification(title, msg, barkEndpoint);
}
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) {
let title = "UptimeKuma Monitor Up";
return await this.postNotification(title, msg, barkEndpoint);
}
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) {
let title = "UptimeKuma Monitor Down";
return await this.postNotification(title, msg, barkEndpoint);
}
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) {
let title = "UptimeKuma Monitor Down";
return await this.postNotification(title, msg, barkEndpoint);
}
if (msg != null) {
let title = "UptimeKuma Message";
return await this.postNotification(title, msg, barkEndpoint);
}
} catch (error) {
throw error;
if (msg != null) {
let title = "UptimeKuma Message";
return await this.postNotification(title, msg, barkEndpoint);
}
}

View File

@@ -12,7 +12,7 @@ class ClickSendSMS extends NotificationProvider {
let config = {
headers: {
"Content-Type": "application/json",
"Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString('base64'),
"Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString("base64"),
"Accept": "text/json",
}
};

View File

@@ -14,8 +14,8 @@ class DingDing extends NotificationProvider {
let params = {
msgtype: "markdown",
markdown: {
title: monitorJSON["name"],
text: `## [${this.statusToString(heartbeatJSON["status"])}] \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`,
title: `[${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}`,
text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`,
}
};
if (this.sendToDingDing(notification, params)) {
@@ -50,7 +50,7 @@ class DingDing extends NotificationProvider {
};
let result = await axios(config);
if (result.data.errmsg == "ok") {
if (result.data.errmsg === "ok") {
return true;
}
return false;

View File

@@ -17,8 +17,8 @@ class Discord extends NotificationProvider {
let discordtestdata = {
username: discordDisplayName,
content: msg,
}
await axios.post(notification.discordWebhookUrl, discordtestdata)
};
await axios.post(notification.discordWebhookUrl, discordtestdata);
return okMsg;
}
@@ -35,7 +35,7 @@ class Discord extends NotificationProvider {
}
// If heartbeatJSON is not null, we go into the normal alerting loop.
if (heartbeatJSON["status"] == DOWN) {
if (heartbeatJSON["status"] === DOWN) {
let discorddowndata = {
username: discordDisplayName,
embeds: [{
@@ -61,16 +61,16 @@ class Discord extends NotificationProvider {
},
],
}],
}
};
if (notification.discordPrefixMessage) {
discorddowndata.content = notification.discordPrefixMessage;
}
await axios.post(notification.discordWebhookUrl, discorddowndata)
await axios.post(notification.discordWebhookUrl, discorddowndata);
return okMsg;
} else if (heartbeatJSON["status"] == UP) {
} else if (heartbeatJSON["status"] === UP) {
let discordupdata = {
username: discordDisplayName,
embeds: [{
@@ -96,17 +96,17 @@ class Discord extends NotificationProvider {
},
],
}],
}
};
if (notification.discordPrefixMessage) {
discordupdata.content = notification.discordPrefixMessage;
}
await axios.post(notification.discordWebhookUrl, discordupdata)
await axios.post(notification.discordWebhookUrl, discordupdata);
return okMsg;
}
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}

View File

@@ -21,7 +21,7 @@ class Feishu extends NotificationProvider {
return okMsg;
}
if (heartbeatJSON["status"] == DOWN) {
if (heartbeatJSON["status"] === DOWN) {
let downdata = {
msg_type: "post",
content: {
@@ -48,7 +48,7 @@ class Feishu extends NotificationProvider {
return okMsg;
}
if (heartbeatJSON["status"] == UP) {
if (heartbeatJSON["status"] === UP) {
let updata = {
msg_type: "post",
content: {

View File

@@ -0,0 +1,47 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { setting } = require("../util-server");
const { getMonitorRelativeURL } = require("../../src/util");
const { DOWN, UP } = require("../../src/util");
class GoogleChat extends NotificationProvider {
name = "GoogleChat";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
// Google Chat message formatting: https://developers.google.com/chat/api/guides/message-formats/basic
let textMsg = "";
if (heartbeatJSON && heartbeatJSON.status === UP) {
textMsg = "✅ Application is back online\n";
} else if (heartbeatJSON && heartbeatJSON.status === DOWN) {
textMsg = "🔴 Application went down\n";
}
if (monitorJSON && monitorJSON.name) {
textMsg += `*${monitorJSON.name}*\n`;
}
textMsg += `${msg}`;
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorJSON) {
textMsg += `\n${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
}
const data = {
"text": textMsg,
};
await axios.post(notification.googleChatWebhookURL, data);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = GoogleChat;

View File

@@ -0,0 +1,42 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Gorush extends NotificationProvider {
name = "gorush";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let platformMapping = {
"ios": 1,
"android": 2,
"huawei": 3,
};
try {
let data = {
"notifications": [
{
"tokens": [ notification.gorushDeviceToken ],
"platform": platformMapping[notification.gorushPlatform],
"message": msg,
// Optional
"title": notification.gorushTitle,
"priority": notification.gorushPriority,
"retry": parseInt(notification.gorushRetry) || 0,
"topic": notification.gorushTopic,
}
]
};
let config = {};
await axios.post(`${notification.gorushServerURL}/api/push`, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Gorush;

View File

@@ -15,7 +15,7 @@ class Gotify extends NotificationProvider {
"message": msg,
"priority": notification.gotifyPriority || 8,
"title": "Uptime-Kuma",
})
});
return okMsg;

View File

@@ -25,9 +25,9 @@ class Line extends NotificationProvider {
"text": "Test Successful!"
}
]
}
await axios.post(lineAPIUrl, testMessage, config)
} else if (heartbeatJSON["status"] == DOWN) {
};
await axios.post(lineAPIUrl, testMessage, config);
} else if (heartbeatJSON["status"] === DOWN) {
let downMessage = {
"to": notification.lineUserID,
"messages": [
@@ -36,9 +36,9 @@ class Line extends NotificationProvider {
"text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
}
]
}
await axios.post(lineAPIUrl, downMessage, config)
} else if (heartbeatJSON["status"] == UP) {
};
await axios.post(lineAPIUrl, downMessage, config);
} else if (heartbeatJSON["status"] === UP) {
let upMessage = {
"to": notification.lineUserID,
"messages": [
@@ -47,12 +47,12 @@ class Line extends NotificationProvider {
"text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
}
]
}
await axios.post(lineAPIUrl, upMessage, config)
};
await axios.post(lineAPIUrl, upMessage, config);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}
}

View File

@@ -8,38 +8,38 @@ class LunaSea extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice
let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice;
try {
if (heartbeatJSON == null) {
let testdata = {
"title": "Uptime Kuma Alert",
"body": "Testing Successful.",
}
await axios.post(lunaseadevice, testdata)
};
await axios.post(lunaseadevice, testdata);
return okMsg;
}
if (heartbeatJSON["status"] == DOWN) {
if (heartbeatJSON["status"] === DOWN) {
let downdata = {
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
}
await axios.post(lunaseadevice, downdata)
};
await axios.post(lunaseadevice, downdata);
return okMsg;
}
if (heartbeatJSON["status"] == UP) {
if (heartbeatJSON["status"] === UP) {
let updata = {
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
}
await axios.post(lunaseadevice, updata)
};
await axios.post(lunaseadevice, updata);
return okMsg;
}
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}

View File

@@ -1,7 +1,7 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const Crypto = require("crypto");
const { debug } = require("../../src/util");
const { log } = require("../../src/util");
class Matrix extends NotificationProvider {
name = "matrix";
@@ -17,11 +17,11 @@ class Matrix extends NotificationProvider {
.slice(0, size)
);
debug("Random String: " + randomString);
log.debug("notification", "Random String: " + randomString);
const roomId = encodeURIComponent(notification.internalRoomId);
debug("Matrix Room ID: " + roomId);
log.debug("notification", "Matrix Room ID: " + roomId);
try {
let config = {

View File

@@ -15,16 +15,21 @@ class Mattermost extends NotificationProvider {
let mattermostTestData = {
username: mattermostUserName,
text: msg,
}
await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
};
await axios.post(notification.mattermostWebhookUrl, mattermostTestData);
return okMsg;
}
const mattermostChannel = notification.mattermostchannel;
let mattermostChannel;
if (typeof notification.mattermostchannel === "string") {
mattermostChannel = notification.mattermostchannel.toLowerCase();
}
const mattermostIconEmoji = notification.mattermosticonemo;
const mattermostIconUrl = notification.mattermosticonurl;
if (heartbeatJSON["status"] == DOWN) {
if (heartbeatJSON["status"] === DOWN) {
let mattermostdowndata = {
username: mattermostUserName,
text: "Uptime Kuma Alert",
@@ -68,7 +73,7 @@ class Mattermost extends NotificationProvider {
mattermostdowndata
);
return okMsg;
} else if (heartbeatJSON["status"] == UP) {
} else if (heartbeatJSON["status"] === UP) {
let mattermostupdata = {
username: mattermostUserName,
text: "Uptime Kuma Alert",

View File

@@ -25,11 +25,11 @@ class NotificationProvider {
if (typeof error.response.data === "string") {
msg += error.response.data;
} else {
msg += JSON.stringify(error.response.data)
msg += JSON.stringify(error.response.data);
}
}
throw new Error(msg)
throw new Error(msg);
}
}

View File

@@ -10,7 +10,7 @@ class Octopush extends NotificationProvider {
try {
// Default - V2
if (notification.octopushVersion == 2 || !notification.octopushVersion) {
if (notification.octopushVersion === 2 || !notification.octopushVersion) {
let config = {
headers: {
"api-key": notification.octopushAPIKey,
@@ -30,14 +30,14 @@ class Octopush extends NotificationProvider {
"purpose": "alert",
"sender": notification.octopushSenderName
};
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config)
} else if (notification.octopushVersion == 1) {
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config);
} else if (notification.octopushVersion === 1) {
let data = {
"user_login": notification.octopushDMLogin,
"api_key": notification.octopushDMAPIKey,
"sms_recipients": notification.octopushDMPhoneNumber,
"sms_sender": notification.octopushDMSenderName,
"sms_type": (notification.octopushDMSMSType == "sms_premium") ? "FR" : "XXX",
"sms_type": (notification.octopushDMSMSType === "sms_premium") ? "FR" : "XXX",
"transactional": "1",
//octopush not supporting non ascii char
"sms_text": msg.replace(/[^\x00-\x7F]/g, ""),
@@ -49,7 +49,7 @@ class Octopush extends NotificationProvider {
},
params: data
};
await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config)
await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config);
} else {
throw new Error("Unknown Octopush version!");
}

View File

@@ -0,0 +1,45 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class OneBot extends NotificationProvider {
name = "OneBot";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let httpAddr = notification.httpAddr;
if (!httpAddr.startsWith("http")) {
httpAddr = "http://" + httpAddr;
}
if (!httpAddr.endsWith("/")) {
httpAddr += "/";
}
let onebotAPIUrl = httpAddr + "send_msg";
let config = {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + notification.accessToken,
}
};
let pushText = "UptimeKuma Alert: " + msg;
let data = {
"auto_escape": true,
"message": pushText,
};
if (notification.msgType === "group") {
data["message_type"] = "group";
data["group_id"] = notification.recieverId;
} else {
data["message_type"] = "private";
data["user_id"] = notification.recieverId;
}
await axios.post(onebotAPIUrl, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = OneBot;

View File

@@ -12,7 +12,7 @@ class PromoSMS extends NotificationProvider {
let config = {
headers: {
"Content-Type": "application/json",
"Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString('base64'),
"Authorization": "Basic " + Buffer.from(notification.promosmsLogin + ":" + notification.promosmsPassword).toString("base64"),
"Accept": "text/json",
}
};
@@ -30,7 +30,7 @@ class PromoSMS extends NotificationProvider {
let error = "Something gone wrong. Api returned " + resp.data.response.status + ".";
this.throwGeneralAxiosError(error);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);

View File

@@ -23,26 +23,26 @@ class Pushbullet extends NotificationProvider {
"type": "note",
"title": "Uptime Kuma Alert",
"body": "Testing Successful.",
}
await axios.post(pushbulletUrl, testdata, config)
} else if (heartbeatJSON["status"] == DOWN) {
};
await axios.post(pushbulletUrl, testdata, config);
} else if (heartbeatJSON["status"] === DOWN) {
let downdata = {
"type": "note",
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
}
await axios.post(pushbulletUrl, downdata, config)
} else if (heartbeatJSON["status"] == UP) {
};
await axios.post(pushbulletUrl, downdata, config);
} else if (heartbeatJSON["status"] === UP) {
let updata = {
"type": "note",
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
}
await axios.post(pushbulletUrl, updata, config)
};
await axios.post(pushbulletUrl, updata, config);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}
}

View File

@@ -0,0 +1,52 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class PushDeer extends NotificationProvider {
name = "PushDeer";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let pushdeerlink = "https://api2.pushdeer.com/message/push";
let valid = msg != null && monitorJSON != null && heartbeatJSON != null;
let title;
if (valid && heartbeatJSON.status === UP) {
title = "## Uptime Kuma: " + monitorJSON.name + " up";
} else if (valid && heartbeatJSON.status === DOWN) {
title = "## Uptime Kuma: " + monitorJSON.name + " down";
} else {
title = "## Uptime Kuma Message";
}
let data = {
"pushkey": notification.pushdeerKey,
"text": title,
"desp": msg.replace(/\n/g, "\n\n"),
"type": "markdown",
};
try {
let res = await axios.post(pushdeerlink, data);
if ("error" in res.data) {
let error = res.data.error;
this.throwGeneralAxiosError(error);
}
if (res.data.content.result.length === 0) {
let error = "Invalid PushDeer key";
this.throwGeneralAxiosError(error);
} else if (JSON.parse(res.data.content.result[0]).success !== "ok") {
let error = "Unknown error";
this.throwGeneralAxiosError(error);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = PushDeer;

View File

@@ -7,40 +7,35 @@ class Pushover extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let pushoverlink = "https://api.pushover.net/1/messages.json"
let pushoverlink = "https://api.pushover.net/1/messages.json";
let data = {
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg,
"user": notification.pushoveruserkey,
"token": notification.pushoverapptoken,
"sound": notification.pushoversounds,
"priority": notification.pushoverpriority,
"title": notification.pushovertitle,
"retry": "30",
"expire": "3600",
"html": 1,
};
if (notification.pushoverdevice) {
data.device = notification.pushoverdevice;
}
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,
}
await axios.post(pushoverlink, data)
await axios.post(pushoverlink, data);
return okMsg;
} else {
data.message += "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"];
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>:" + heartbeatJSON["time"],
"user": notification.pushoveruserkey,
"token": notification.pushoverapptoken,
"sound": notification.pushoversounds,
"priority": notification.pushoverpriority,
"title": notification.pushovertitle,
"retry": "30",
"expire": "3600",
"html": 1,
}
await axios.post(pushoverlink, data)
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}

View File

@@ -19,10 +19,10 @@ class Pushy extends NotificationProvider {
"badge": 1,
"sound": "ping.aiff"
}
})
});
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}
}

View File

@@ -2,7 +2,7 @@ const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const Slack = require("./slack");
const { setting } = require("../util-server");
const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util");
const { getMonitorRelativeURL, DOWN } = require("../../src/util");
class RocketChat extends NotificationProvider {

View File

@@ -0,0 +1,44 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class SerwerSMS extends NotificationProvider {
name = "serwersms";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let config = {
headers: {
"Content-Type": "application/json",
}
};
let data = {
"username": notification.serwersmsUsername,
"password": notification.serwersmsPassword,
"phone": notification.serwersmsPhoneNumber,
"text": msg.replace(/[^\x00-\x7F]/g, ""),
"sender": notification.serwersmsSenderName,
};
let resp = await axios.post("https://api2.serwersms.pl/messages/send_sms", data, config);
if (!resp.data.success) {
if (resp.data.error) {
let error = `SerwerSMS.pl API returned error code ${resp.data.error.code} (${resp.data.error.type}) with error message: ${resp.data.error.message}`;
this.throwGeneralAxiosError(error);
} else {
let error = "SerwerSMS.pl API returned an unexpected response";
this.throwGeneralAxiosError(error);
}
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = SerwerSMS;

View File

@@ -16,10 +16,10 @@ class Signal extends NotificationProvider {
};
let config = {};
await axios.post(notification.signalURL, data, config)
await axios.post(notification.signalURL, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}
}

View File

@@ -1,6 +1,6 @@
const nodemailer = require("nodemailer");
const NotificationProvider = require("./notification-provider");
const { DOWN, UP } = require("../../src/util");
const { DOWN } = require("../../src/util");
class SMTP extends NotificationProvider {
@@ -14,9 +14,21 @@ class SMTP extends NotificationProvider {
secure: notification.smtpSecure,
tls: {
rejectUnauthorized: notification.smtpIgnoreTLSError || false,
},
}
};
// Fix #1129
if (notification.smtpDkimDomain) {
config.dkim = {
domainName: notification.smtpDkimDomain,
keySelector: notification.smtpDkimKeySelector,
privateKey: notification.smtpDkimPrivateKey,
hashAlgo: notification.smtpDkimHashAlgo,
headerFieldNames: notification.smtpDkimheaderFieldNames,
skipFields: notification.smtpDkimskipFields,
};
}
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
if (notification.smtpUsername || notification.smtpPassword) {
config.auth = {

View File

@@ -0,0 +1,41 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { setting } = require("../util-server");
const { getMonitorRelativeURL } = require("../../src/util");
class Stackfield extends NotificationProvider {
name = "stackfield";
async send(notification, msg, monitorJSON = null) {
let okMsg = "Sent Successfully.";
try {
// Stackfield message formatting: https://www.stackfield.com/help/formatting-messages-2001
let textMsg = "+Uptime Kuma Alert+";
if (monitorJSON && monitorJSON.name) {
textMsg += `\n*${monitorJSON.name}*`;
}
textMsg += `\n${msg}`;
const baseURL = await setting("primaryBaseURL");
if (baseURL) {
textMsg += `\n${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
}
const data = {
"Title": textMsg,
};
await axios.post(notification.stackfieldwebhookURL, data);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Stackfield;

View File

@@ -0,0 +1,23 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class TechulusPush extends NotificationProvider {
name = "PushByTechulus";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, {
"title": "Uptime-Kuma",
"body": msg,
});
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = TechulusPush;

View File

@@ -14,12 +14,12 @@ class Telegram extends NotificationProvider {
chat_id: notification.telegramChatID,
text: msg,
},
})
});
return okMsg;
} catch (error) {
let msg = (error.response.data.description) ? error.response.data.description : "Error without description"
throw new Error(msg)
let msg = (error.response.data.description) ? error.response.data.description : "Error without description";
throw new Error(msg);
}
}
}

View File

@@ -24,17 +24,17 @@ class Webhook extends NotificationProvider {
config = {
headers: finalData.getHeaders(),
}
};
} else {
finalData = data;
}
await axios.post(notification.webhookURL, finalData, config)
await axios.post(notification.webhookURL, finalData, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error)
this.throwGeneralAxiosError(error);
}
}

View File

@@ -0,0 +1,47 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class WeCom extends NotificationProvider {
name = "WeCom";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let WeComUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + notification.weComBotKey;
let config = {
headers: {
"Content-Type": "application/json"
}
};
let body = this.composeMessage(heartbeatJSON, msg);
await axios.post(WeComUrl, body, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
composeMessage(heartbeatJSON, msg) {
let title;
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) {
title = "UptimeKuma Monitor Up";
}
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) {
title = "UptimeKuma Monitor Down";
}
if (msg != null) {
title = "UptimeKuma Message";
}
return {
msgtype: "text",
text: {
content: title + msg
}
};
}
}
module.exports = WeCom;

View File

@@ -12,6 +12,7 @@ const ClickSendSMS = require("./notification-providers/clicksendsms");
const Pushbullet = require("./notification-providers/pushbullet");
const Pushover = require("./notification-providers/pushover");
const Pushy = require("./notification-providers/pushy");
const TechulusPush = require("./notification-providers/techulus-push");
const RocketChat = require("./notification-providers/rocket-chat");
const Signal = require("./notification-providers/signal");
const Slack = require("./notification-providers/slack");
@@ -23,13 +24,22 @@ const Feishu = require("./notification-providers/feishu");
const AliyunSms = require("./notification-providers/aliyun-sms");
const DingDing = require("./notification-providers/dingding");
const Bark = require("./notification-providers/bark");
const { log } = require("../src/util");
const SerwerSMS = require("./notification-providers/serwersms");
const Stackfield = require("./notification-providers/stackfield");
const WeCom = require("./notification-providers/wecom");
const GoogleChat = require("./notification-providers/google-chat");
const Gorush = require("./notification-providers/gorush");
const Alerta = require("./notification-providers/alerta");
const OneBot = require("./notification-providers/onebot");
const PushDeer = require("./notification-providers/pushdeer");
class Notification {
providerList = {};
static init() {
console.log("Prepare Notification Providers");
log.info("notification", "Prepare Notification Providers");
this.providerList = {};
@@ -51,6 +61,7 @@ class Notification {
new Pushbullet(),
new Pushover(),
new Pushy(),
new TechulusPush(),
new RocketChat(),
new Signal(),
new Slack(),
@@ -58,6 +69,14 @@ class Notification {
new Telegram(),
new Webhook(),
new Bark(),
new SerwerSMS(),
new Stackfield(),
new WeCom(),
new GoogleChat(),
new Gorush(),
new Alerta(),
new OneBot(),
new PushDeer(),
];
for (let item of list) {
@@ -90,27 +109,27 @@ class Notification {
}
static async save(notification, notificationID, userID) {
let bean
let bean;
if (notificationID) {
bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
notificationID,
userID,
])
]);
if (! bean) {
throw new Error("notification not found")
throw new Error("notification not found");
}
} else {
bean = R.dispense("notification")
bean = R.dispense("notification");
}
bean.name = notification.name;
bean.user_id = userID;
bean.config = JSON.stringify(notification);
bean.is_default = notification.isDefault || false;
await R.store(bean)
await R.store(bean);
if (notification.applyExisting) {
await applyNotificationEveryMonitor(bean.id, userID);
@@ -123,13 +142,13 @@ class Notification {
let bean = await R.findOne("notification", " id = ? AND user_id = ? ", [
notificationID,
userID,
])
]);
if (! bean) {
throw new Error("notification not found")
throw new Error("notification not found");
}
await R.trash(bean)
await R.trash(bean);
}
static checkApprise() {
@@ -140,6 +159,13 @@ class Notification {
}
/**
* Adds a new monitor to the database.
* @param {number} userID The ID of the user that owns this monitor.
* @param {string} name The name of this monitor.
*
* Generated by Trelent
*/
async function applyNotificationEveryMonitor(notificationID, userID) {
let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [
userID
@@ -149,17 +175,17 @@ async function applyNotificationEveryMonitor(notificationID, userID) {
let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [
monitors[i].id,
notificationID,
])
]);
if (! checkNotification) {
let relation = R.dispense("monitor_notification");
relation.monitor_id = monitors[i].id;
relation.notification_id = notificationID;
await R.store(relation)
await R.store(relation);
}
}
}
module.exports = {
Notification,
}
};

View File

@@ -4,20 +4,20 @@ 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)
return passwordHashOld.verify(password, hash);
}
return bcrypt.compareSync(password, hash);
}
};
function isSHA1(hash) {
return (typeof hash === "string" && hash.startsWith("sha1"))
return (typeof hash === "string" && hash.startsWith("sha1"));
}
exports.needRehash = function (hash) {
return isSHA1(hash);
}
};

View File

@@ -8,6 +8,13 @@ const util = require("./util-server");
module.exports = Ping;
/**
* @param {string} host - The host to ping
* @param {object} [options] - Options for the ping command
* @param {array|string} [options.args] - Arguments to pass to the ping command
*
* Generated by Trelent
*/
function Ping(host, options) {
if (!host) {
throw new Error("You must specify a host to ping!");
@@ -48,7 +55,7 @@ function Ping(host, options) {
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", host ];
this._regmatch = /=([0-9.]+?) ms/;
} else if (util.FBSD) {
} else if (util.BSD) {
this._bin = "/sbin/ping";
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", host ];
@@ -125,6 +132,11 @@ Ping.prototype.send = function (callback) {
}
});
/**
* @param {Function} callback
*
* Generated by Trelent
*/
function onEnd() {
let stdout = this.stdout._stdout;
let stderr = this.stderr._stderr;

View File

@@ -1,4 +1,5 @@
const PrometheusClient = require("prom-client");
const { log } = require("../src/util");
const commonLabels = [
"monitor_name",
@@ -8,24 +9,24 @@ const commonLabels = [
"monitor_port",
];
const monitor_cert_days_remaining = new PrometheusClient.Gauge({
const monitorCertDaysRemaining = new PrometheusClient.Gauge({
name: "monitor_cert_days_remaining",
help: "The number of days remaining until the certificate expires",
labelNames: commonLabels
});
const monitor_cert_is_valid = new PrometheusClient.Gauge({
const monitorCertIsValid = new PrometheusClient.Gauge({
name: "monitor_cert_is_valid",
help: "Is the certificate still valid? (1 = Yes, 0= No)",
labelNames: commonLabels
});
const monitor_response_time = new PrometheusClient.Gauge({
const monitorResponseTime = new PrometheusClient.Gauge({
name: "monitor_response_time",
help: "Monitor Response Time (ms)",
labelNames: commonLabels
});
const monitor_status = new PrometheusClient.Gauge({
const monitorStatus = new PrometheusClient.Gauge({
name: "monitor_status",
help: "Monitor Status (1 = UP, 0= DOWN)",
labelNames: commonLabels
@@ -48,42 +49,58 @@ class Prometheus {
if (typeof tlsInfo !== "undefined") {
try {
let is_valid = 0;
if (tlsInfo.valid == true) {
is_valid = 1;
let isValid;
if (tlsInfo.valid === true) {
isValid = 1;
} else {
is_valid = 0;
isValid = 0;
}
monitor_cert_is_valid.set(this.monitorLabelValues, is_valid);
monitorCertIsValid.set(this.monitorLabelValues, isValid);
} catch (e) {
console.error(e);
log.error("prometheus", "Caught error");
log.error("prometheus", e);
}
try {
monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining);
if (tlsInfo.certInfo != null) {
monitorCertDaysRemaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining);
}
} catch (e) {
console.error(e);
log.error("prometheus", "Caught error");
log.error("prometheus", e);
}
}
try {
monitor_status.set(this.monitorLabelValues, heartbeat.status);
monitorStatus.set(this.monitorLabelValues, heartbeat.status);
} catch (e) {
console.error(e);
log.error("prometheus", "Caught error");
log.error("prometheus", e);
}
try {
if (typeof heartbeat.ping === "number") {
monitor_response_time.set(this.monitorLabelValues, heartbeat.ping);
monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping);
} else {
// Is it good?
monitor_response_time.set(this.monitorLabelValues, -1);
monitorResponseTime.set(this.monitorLabelValues, -1);
}
} catch (e) {
log.error("prometheus", "Caught error");
log.error("prometheus", e);
}
}
remove() {
try {
monitorCertDaysRemaining.remove(this.monitorLabelValues);
monitorCertIsValid.remove(this.monitorLabelValues);
monitorResponseTime.remove(this.monitorLabelValues);
monitorStatus.remove(this.monitorLabelValues);
} catch (e) {
console.error(e);
}
}
}
module.exports = {

189
server/proxy.js Normal file
View File

@@ -0,0 +1,189 @@
const { R } = require("redbean-node");
const HttpProxyAgent = require("http-proxy-agent");
const HttpsProxyAgent = require("https-proxy-agent");
const SocksProxyAgent = require("socks-proxy-agent");
const { debug } = require("../src/util");
const { UptimeKumaServer } = require("./uptime-kuma-server");
class Proxy {
static SUPPORTED_PROXY_PROTOCOLS = [ "http", "https", "socks", "socks5", "socks4" ]
/**
* Saves and updates given proxy entity
*
* @param proxy
* @param proxyID
* @param userID
* @return {Promise<Bean>}
*/
static async save(proxy, proxyID, userID) {
let bean;
if (proxyID) {
bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]);
if (!bean) {
throw new Error("proxy not found");
}
} else {
bean = R.dispense("proxy");
}
// Make sure given proxy protocol is supported
if (!this.SUPPORTED_PROXY_PROTOCOLS.includes(proxy.protocol)) {
throw new Error(`
Unsupported proxy protocol "${proxy.protocol}.
Supported protocols are ${this.SUPPORTED_PROXY_PROTOCOLS.join(", ")}."`
);
}
// When proxy is default update deactivate old default proxy
if (proxy.default) {
await R.exec("UPDATE proxy SET `default` = 0 WHERE `default` = 1");
}
bean.user_id = userID;
bean.protocol = proxy.protocol;
bean.host = proxy.host;
bean.port = proxy.port;
bean.auth = proxy.auth;
bean.username = proxy.username;
bean.password = proxy.password;
bean.active = proxy.active || true;
bean.default = proxy.default || false;
await R.store(bean);
if (proxy.applyExisting) {
await applyProxyEveryMonitor(bean.id, userID);
}
return bean;
}
/**
* Deletes proxy with given id and removes it from monitors
*
* @param proxyID
* @param userID
* @return {Promise<void>}
*/
static async delete(proxyID, userID) {
const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]);
if (!bean) {
throw new Error("proxy not found");
}
// Delete removed proxy from monitors if exists
await R.exec("UPDATE monitor SET proxy_id = null WHERE proxy_id = ?", [ proxyID ]);
// Delete proxy from list
await R.trash(bean);
}
/**
* Create HTTP and HTTPS agents related with given proxy bean object
*
* @param proxy proxy bean object
* @param options http and https agent options
* @return {{httpAgent: Agent, httpsAgent: Agent}}
*/
static createAgents(proxy, options) {
const { httpAgentOptions, httpsAgentOptions } = options || {};
let agent;
let httpAgent;
let httpsAgent;
const proxyOptions = {
protocol: proxy.protocol,
host: proxy.host,
port: proxy.port,
};
if (proxy.auth) {
proxyOptions.auth = `${proxy.username}:${proxy.password}`;
}
debug(`Proxy Options: ${JSON.stringify(proxyOptions)}`);
debug(`HTTP Agent Options: ${JSON.stringify(httpAgentOptions)}`);
debug(`HTTPS Agent Options: ${JSON.stringify(httpsAgentOptions)}`);
switch (proxy.protocol) {
case "http":
case "https":
httpAgent = new HttpProxyAgent({
...httpAgentOptions || {},
...proxyOptions
});
httpsAgent = new HttpsProxyAgent({
...httpsAgentOptions || {},
...proxyOptions,
});
break;
case "socks":
case "socks5":
case "socks4":
agent = new SocksProxyAgent({
...httpAgentOptions,
...httpsAgentOptions,
...proxyOptions,
});
httpAgent = agent;
httpsAgent = agent;
break;
default: throw new Error(`Unsupported proxy protocol provided. ${proxy.protocol}`);
}
return {
httpAgent,
httpsAgent
};
}
/**
* Reload proxy settings for current monitors
* @returns {Promise<void>}
*/
static async reloadProxy() {
const server = UptimeKumaServer.getInstance();
let updatedList = await R.getAssoc("SELECT id, proxy_id FROM monitor");
for (let monitorID in server.monitorList) {
let monitor = server.monitorList[monitorID];
if (updatedList[monitorID]) {
monitor.proxy_id = updatedList[monitorID].proxy_id;
}
}
}
}
/**
* Applies given proxy id to monitors
*
* @param proxyID
* @param userID
* @return {Promise<void>}
*/
async function applyProxyEveryMonitor(proxyID, userID) {
// Find all monitors with id and proxy id
const monitors = await R.getAll("SELECT id, proxy_id FROM monitor WHERE user_id = ?", [ userID ]);
// Update proxy id not match with given proxy id
for (const monitor of monitors) {
if (monitor.proxy_id !== proxyID) {
await R.exec("UPDATE monitor SET proxy_id = ? WHERE id = ?", [ proxyID, monitor.id ]);
}
}
}
module.exports = {
Proxy,
};

View File

@@ -1,5 +1,5 @@
const { RateLimiter } = require("limiter");
const { debug } = require("../src/util");
const { log } = require("../src/util");
class KumaRateLimiter {
constructor(config) {
@@ -9,7 +9,7 @@ class KumaRateLimiter {
async pass(callback, num = 1) {
const remainingRequests = await this.removeTokens(num);
debug("Rate Limit (remainingRequests):" + remainingRequests);
log.info("rate-limit", "remaining requests: " + remainingRequests);
if (remainingRequests < 0) {
if (callback) {
callback({
@@ -34,6 +34,14 @@ const loginRateLimiter = new KumaRateLimiter({
errorMessage: "Too frequently, try again later."
});
const twoFaRateLimiter = new KumaRateLimiter({
tokensPerInterval: 30,
interval: "minute",
fireImmediately: true,
errorMessage: "Too frequently, try again later."
});
module.exports = {
loginRateLimiter
loginRateLimiter,
twoFaRateLimiter,
};

Some files were not shown because too many files have changed in this diff Show More