Compare commits

...

796 Commits

Author SHA1 Message Date
Louis Lam
71c34694b7 Update to 1.22.0-beta.0 2023-06-11 15:17:26 +08:00
Louis Lam
2128ed5ce3 Update dependencies 2023-06-11 14:44:05 +08:00
Louis Lam
09ab6a015b Merge pull request #3046 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-06-11 14:36:20 +08:00
Louis Lam
ec858eb67a Merge remote-tracking branch 'origin/master' into weblate-uptime-kuma-uptime-kuma
# Conflicts:
#	src/lang/de-DE.json
2023-06-11 14:35:10 +08:00
Louis Lam
c4c3fc81b2 Merge pull request #2693 from julian-piehl/group-monitors
Group monitors
2023-06-11 14:09:02 +08:00
Arin Faraj
8aa577529f Added translation using Weblate (Kurdish (Central))
Co-authored-by: Arin Faraj <arin.abdul99@gmail.com>
2023-06-10 20:28:20 +00:00
Manh PHam
cdd5067b17 Added translation using Weblate (Xhosa)
Co-authored-by: Manh PHam <manh.pham0997@gmail.com>
2023-06-10 20:28:20 +00:00
Oskar Fagerfjäll
5fdb01308a Translated using Weblate (Swedish)
Currently translated at 18.6% (139 of 746 strings)

Co-authored-by: Oskar Fagerfjäll <oskar.fagerfjall@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sv/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:20 +00:00
Alexandre
eb1a1d0ac7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 78.4% (585 of 746 strings)

Co-authored-by: Alexandre <alexandre@lopes.eng.br>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
mottcha
a1fc283b3c Translated using Weblate (Japanese)
Currently translated at 69.0% (515 of 746 strings)

Translated using Weblate (Japanese)

Currently translated at 69.0% (515 of 746 strings)

Co-authored-by: mottcha <yuki627f@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
deluxghost
419b684433 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (746 of 746 strings)

Co-authored-by: deluxghost <deluxghost@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Lê Huy Mạnh Tân
8bc139d8c1 Translated using Weblate (Vietnamese)
Currently translated at 62.1% (464 of 746 strings)

Co-authored-by: Lê Huy Mạnh Tân <tanmanh350@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Artur Wróblewski
91dfd8dfaa Translated using Weblate (Polish)
Currently translated at 96.6% (721 of 746 strings)

Co-authored-by: Artur Wróblewski <krypalkora1984@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Marco
1f405cf2a0 Translated using Weblate (German)
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (746 of 746 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Cyril59310
cf61077dd8 Translated using Weblate (French)
Currently translated at 99.8% (745 of 746 strings)

Translated using Weblate (French)

Currently translated at 97.7% (729 of 746 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
TKB Studios
4396e0d4d8 Translated using Weblate (French)
Currently translated at 100.0% (722 of 722 strings)

Co-authored-by: TKB Studios <alessio.dambrosio@outlook.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Henry Wu
240db1d173 Translated using Weblate (Chinese (Traditional))
Currently translated at 94.0% (678 of 721 strings)

Co-authored-by: Henry Wu <me@henry40408.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
AnnAngela
ef06b5376d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
deluxghost
186d733134 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: deluxghost <deluxghost@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
R1KO
225ba61e22 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: R1KO <r1kobeats@i.ua>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Furkan İ
11b32ce553 Translated using Weblate (Turkish)
Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: Furkan İ <developer@furkanipek.com.tr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
Filip#0475
3707919025 Translated using Weblate (Slovak)
Currently translated at 28.1% (203 of 721 strings)

Co-authored-by: Filip#0475 <surinfilip@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:19 +00:00
kokofixcomputers
d10e378fb1 Translated using Weblate (French)
Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: kokofixcomputers <koko@trashmail.se>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Alex Javadi
370328c3b8 Translated using Weblate (Persian)
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Persian)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Persian)

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Persian)

Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Sergio Leon
1d8a82ae3e Translated using Weblate (Spanish)
Currently translated at 99.1% (715 of 721 strings)

Co-authored-by: Sergio Leon <serge@1nationgfx.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
mickeydarrenlau
7da336e975 Translated using Weblate (Malay)
Currently translated at 3.6% (26 of 721 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (721 of 721 strings)

Added translation using Weblate (Malay)

Co-authored-by: mickeydarrenlau <darrenwjlau@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ms/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
@shiroo
b8c12cca2a Translated using Weblate (Arabic)
Currently translated at 94.3% (680 of 721 strings)

Co-authored-by: @shiroo <elrayan202021@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Cyril59310
88fcfcc6fc Translated using Weblate (French)
Currently translated at 100.0% (721 of 721 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Petros Giannhs
fcb22f7d05 Translated using Weblate (Greek)
Currently translated at 92.3% (666 of 721 strings)

Co-authored-by: Petros Giannhs <souvlaki420@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/el/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Windless
5be41990bc Translated using Weblate (Chinese (Traditional))
Currently translated at 92.4% (665 of 719 strings)

Co-authored-by: Windless <eason2008212@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
andershh
09149f50e0 Translated using Weblate (Danish)
Currently translated at 78.1% (562 of 719 strings)

Co-authored-by: andershh <ahh@jlbr.dk>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Buchtič
8f60274582 Translated using Weblate (Czech)
Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (719 of 719 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Buchtič <martin.buchta@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Tomasz Ad
7dadac3ebe Translated using Weblate (Polish)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Tomasz Ad <djtms84@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Hossein Niyumard
28c29f755d Translated using Weblate (Persian)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Hossein Niyumard <niyumard@riseup.net>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Yoswaris Lawpaiboon
b426840b5b Translated using Weblate (Thai)
Currently translated at 86.4% (623 of 721 strings)

Translated using Weblate (Thai)

Currently translated at 85.8% (617 of 719 strings)

Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:18 +00:00
Lance
4f2d39d5fc Translated using Weblate (Chinese (Traditional))
Currently translated at 92.3% (664 of 719 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 92.2% (663 of 719 strings)

Co-authored-by: Lance <2124757129@qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
AnnAngela
4012fc6964 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
Ömer Faruk Genç
d1b52bc098 Translated using Weblate (Turkish)
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
Michal
c9a32f9dbb Translated using Weblate (Czech)
Currently translated at 99.5% (743 of 746 strings)

Translated using Weblate (Czech)

Currently translated at 98.9% (738 of 746 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
stanol
b884f82de6 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (719 of 719 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
Thiago Felipe Cruz E Souza
65928a26c7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 75.6% (544 of 719 strings)

Co-authored-by: Thiago Felipe Cruz E Souza <thiago.felipe@tutanota.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
DoyunShin
abe00efa7f Translated using Weblate (Korean)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: DoyunShin <doyun.shin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
Unai Tolosa Pontesta
0c364fc288 Translated using Weblate (Basque)
Currently translated at 75.7% (545 of 719 strings)

Co-authored-by: Unai Tolosa Pontesta <utolosa002@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/eu/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
MrEddX
0d21529037 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (746 of 746 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (722 of 722 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (721 of 721 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-06-10 20:28:17 +00:00
Louis Lam
fea8ef8367 Update bug_report.yaml 2023-06-09 20:50:13 +08:00
Louis Lam
37031fb9a7 Merge pull request #3222 from chakflying/fix/mysql-aborted-connection
Fix: Try to close mysql connection properly
2023-06-08 00:26:18 +08:00
Nelson Chan
58ec53fb1d Fix: Try to close mysql connection properly 2023-06-06 20:28:51 +08:00
Peace
57190b58c6 fix: dont show ping on details page of groups 2023-06-03 20:55:24 +02:00
Peace
6c2948d2de fix: list collapse storage 2023-06-03 20:54:52 +02:00
Louis Lam
68f389868c Update bug_report.yaml 2023-06-03 16:25:49 +08:00
Louis Lam
af5d7cbb0b Update README.md 2023-06-03 16:22:51 +08:00
Peace
56f448bfe5 fix: maintenance heredity 2023-05-31 21:29:20 +02:00
Peace
2b46da0f47 style: fix linting 2023-05-31 21:19:46 +02:00
Peace
9bd76c2795 Merge branch 'master' into group-monitors 2023-05-31 20:51:33 +02:00
Louis Lam
4b3a2ee71b Merge pull request #3211 from kiznick/badge-generator
Add i18n variable for Badge Generator #2915
2023-05-31 18:00:13 +08:00
Yoswaris Lawpaiboon
1634df5a39 Update en.json 2023-05-31 16:00:38 +07:00
Louis Lam
039fdb0730 Merge pull request #2915 from kiznick/badge-generator
Feat: Badge Generator
2023-05-31 16:09:13 +08:00
Louis Lam
20af2d9d95 Merge pull request #3209 from chakflying/fix/apikey-modal-layout
Fix: Fix incorrect modal layout in generate api-key
2023-05-31 15:09:58 +08:00
Nelson Chan
04806ba4f3 Fix: Fix incorrect modal layout 2023-05-31 09:26:54 +08:00
Yoswaris Lawpaiboon
3ff910a8f8 Fix Modal 2023-05-30 20:06:53 +07:00
Louis Lam
343a1d3344 Merge pull request #3203 from CommanderStorm/applied_timezone_formatting
chore: Made sure that every notification provider uses `timezone`/`localTime`
2023-05-30 20:36:32 +08:00
Louis Lam
f1c184c30c Update README.md 2023-05-30 17:37:53 +08:00
Frank Elsinga
f3c09f2bbd made every Notification provider supply time like dingding after #3152 2023-05-29 19:24:40 +02:00
Yoswaris Lawpaiboon
85eb084305 Setting Modal 2023-05-29 20:11:06 +07:00
Louis Lam
0735f12d19 Merge pull request #2594 from skaempfe/skaempfe#2593
Improvement: Support TLS Expiry alerts also for CA certs in cert chain
2023-05-28 22:13:48 +08:00
Louis Lam
8ed2b59410 Resolve conflict 2023-05-26 21:38:51 +08:00
Louis Lam
0b8dddba24 Merge remote-tracking branch 'origin/master' into skaempfe#2593
# Conflicts:
#	server/model/monitor.js
#	src/pages/Details.vue
2023-05-26 21:32:58 +08:00
Louis Lam
2114295381 Merge pull request #3052 from chakflying/ui/monitor-page-design-mobile
UI: Improve monitor page layout on mobile
2023-05-26 18:30:43 +08:00
Louis Lam
bc95875aa0 Merge pull request #3156 from maximilian-krauss/feat/add-pushover-ttl
feat: Adds message ttl to pushover notification
2023-05-26 18:18:24 +08:00
Louis Lam
c1efe0f26d Add a warning for Node.js >= 20 2023-05-26 18:09:05 +08:00
Maximilian Krauß
a0d0d5b015 fix: sends pushover ttl only if defined 2023-05-26 07:27:43 +02:00
Maximilian Krauß
8d05d80a5f feat: Adds message ttl to pushover notification 2023-05-26 07:27:43 +02:00
Louis Lam
36942de329 Merge pull request #2916 from lukasbableck/master
Add safe-area-inset-bottom padding to bottom-nav
2023-05-25 17:53:44 +08:00
Louis Lam
771ca09331 npm update (mainly for socket.io) 2023-05-25 13:41:35 +08:00
Louis Lam
3cb287a40e Merge pull request #3009 from chakflying/ui/url-more-monitor-types
UI: Support more monitor types in URL field
2023-05-24 20:46:48 +08:00
Nelson Chan
83a59bd984 Fix: Add password filtering 2023-05-22 04:17:45 +08:00
Nelson Chan
446b5fa9e4 UI: Support more monitor types in URL field 2023-05-21 16:03:05 +08:00
Zaid-maker
0d1b5321ad 🚀 Update legacy deps 2023-05-21 12:02:02 +08:00
Louis Lam
1e1cc86a10 Update Apprise to 1.4.0 2023-05-20 01:46:07 +08:00
Louis Lam
9dc02bb8e2 Update .gitignore 2023-05-16 21:57:08 +08:00
Louis Lam
bb15fa0179 Merge pull request #3154 from chakflying/fix/clear-data-remove-worker-thread
Fix: Remove use of worker threads in clear-old-data
2023-05-16 19:51:20 +08:00
Yoswaris Lawpaiboon
966066b897 Update src/components/BadgeGeneratorDialog.vue
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-05-15 13:56:59 +07:00
Louis Lam
8d24891b8e Merge pull request #3054 from TechWilk/keyword-not-found-whitespace
Trim before truncating "keword not found" message
2023-05-13 18:36:04 +08:00
Louis Lam
ba7de3fd37 Merge pull request #3152 from AnnAngela/patch-1
feat: show time as server timezone in dingding notification
2023-05-13 18:15:05 +08:00
Nelson Chan
80c8fd7372 Chore: Remove util-worker 2023-05-13 01:51:23 +08:00
Nelson Chan
a27386bb92 Fix: Use croner for clear-old-data 2023-05-13 00:59:58 +08:00
AnnAngela
ce70b3fc62 feat: add a space to separate the words 2023-05-12 22:14:59 +08:00
AnnAngela
06fba5b55a feat: show time as server timezone in dingding notification 2023-05-12 22:04:44 +08:00
Louis Lam
f2c294e9e5 Merge pull request #3150 from theitguycj/master
Update README.md
2023-05-12 13:56:03 +08:00
The IT Guy CJ
332e54937e Update README.md 2023-05-11 23:19:09 -05:00
Louis Lam
a1adc30a89 Fix: Add back PagerTree 2023-05-11 14:56:42 +08:00
Louis Lam
6ce882ad4a Update README.md 2023-05-10 22:51:44 +08:00
Louis Lam
e392d12585 Mention in the README that Node.js 20 is not supported due to a weird issue 2023-05-09 23:37:51 +08:00
Louis Lam
253214ad2b Merge pull request #3024 from chakflying/feat/edit-tag-multiselect
UI: Use vue-multiselect in Edit Tag & Styling Fixes
2023-05-09 20:43:30 +08:00
Louis Lam
33de7bdb1c Merge conflict 2023-05-09 00:45:31 +08:00
Louis Lam
7f5d0e5490 Merge remote-tracking branch 'origin/1.21.X'
# Conflicts:
#	package-lock.json
2023-05-09 00:42:11 +08:00
Louis Lam
1a344c1371 Update to 1.21.3 2023-05-09 00:28:29 +08:00
Louis Lam
28b0f8fc00 Update dependencies 2023-05-08 22:52:57 +08:00
Louis Lam
0eaaa8b6fa Minor 2023-05-08 22:52:41 +08:00
Louis Lam
5cd506e340 Minor 2023-05-08 22:39:32 +08:00
Louis Lam
f0beccf6bf Fix Same As Server Timezone do not save correctly 2023-05-08 22:14:58 +08:00
Louis Lam
72c16c3aa2 Fix eslint warnings 2023-05-08 04:26:11 +08:00
Louis Lam
aa8454b73f Slightly improve error check on maintenance edit page 2023-05-08 04:14:24 +08:00
Louis Lam
d23cb0b382 Fix maintenance do not start after 1.21.2 2023-05-08 04:08:30 +08:00
Nelson Chan
9975050872 Chore: Fix line break 2023-05-07 23:20:28 +08:00
Nelson Chan
f8c2909576 UI: Improve styling 2023-05-07 23:20:28 +08:00
Nelson Chan
fcfe13e52d Feat: Use vue-multiselect in Edit Tag 2023-05-07 23:20:28 +08:00
Nelson Chan
9f51115a19 Chore: Fix lint 2023-05-07 23:20:03 +08:00
Nelson Chan
4057ca6e72 UI: Improve monitor page on mobile 2023-05-07 23:20:03 +08:00
Louis Lam
8a3bce44ef Update dependenices 2023-05-02 16:22:00 +08:00
Louis Lam
dfe6f52f6a Add test for Node.js 20, drop 19 2023-05-02 16:17:37 +08:00
Louis Lam
333a631389 Merge pull request #3106 from shihaamabr/master
Fix typo in dashboard TCP Port items
2023-04-29 12:44:31 +08:00
Shihaam Abdul Rahman
eaa948579b Fix typo in dashboard TCP Port times 2023-04-27 12:34:01 +05:00
Louis Lam
74dd07c3ca Merge pull request #3101 from stumpylog/feature/cloudflare-pkgs
Install cloudflared via Cloudflare Package Repository
2023-04-25 21:10:25 +08:00
Louis Lam
f75cf3a186 Merge pull request #2905 from Sharknoon/ntfy-bearer-authorization
Added option for notification provider ntfy to use access tokens
2023-04-25 18:24:44 +08:00
Louis Lam
a3e31b22bc Minor 2023-04-25 18:22:17 +08:00
Louis Lam
078d1f96a5 Better handling for old added ntfy notifications 2023-04-25 18:17:32 +08:00
Louis Lam
8207f16396 Merge remote-tracking branch 'origin/master' into ntfy-bearer-authorization 2023-04-25 18:07:52 +08:00
Trenton Holmes
ba82abe5f3 Updates the install of cloudflared to utilize the Cloudflare Package Repository 2023-04-24 06:47:44 -07:00
Louis Lam
eb9c748071 Merge pull request #3006 from chakflying/ui/tags-settings-mobile
UI: Improve Tags settings design on mobile
2023-04-17 16:58:57 +08:00
Yoswaris Lawpaiboon
3579520575 Fix Eslint
Co-authored-by: Nelson Chan <3271800+chakflying@users.noreply.github.com>
2023-04-12 20:09:04 +07:00
Yoswaris Lawpaiboon
030faddd1c Merge branch 'louislam:master' into badge-generator 2023-04-12 12:02:36 +07:00
Christopher Wilkinson
0e516a42e5 Trim before truncating "keword not found" message 2023-04-11 16:57:30 +01:00
Louis Lam
680dccefea Merge pull request #2868 from chakflying/update-chartjs
Chore: Update chart.js & improve performance
2023-04-11 19:01:47 +08:00
Louis Lam
8c9423f4de Merge conflicts manually 2023-04-11 19:01:17 +08:00
Louis Lam
f433f33418 Merge remote-tracking branch 'origin/master' into update-chartjs
# Conflicts:
#	package-lock.json
#	package.json
2023-04-11 18:58:20 +08:00
Louis Lam
d4a31cf02a Merge pull request #2867 from Small6oy/grpc-patch
Resolved issue with using IP Address as GRPC URL
2023-04-11 18:55:43 +08:00
Louis Lam
a7588adc52 Merge branch 'master' into grpc-patch 2023-04-11 18:55:27 +08:00
Louis Lam
6356b1e50a Merge pull request #2961 from chakflying/feat/flush-wal
Chore: Flush WAL on shutdown
2023-04-11 18:53:58 +08:00
Louis Lam
af6e01ee3a Merge pull request #3010 from chakflying/fix/grpc-invalid-regex
Fix: Remove invalid gRPC url regex
2023-04-11 18:43:51 +08:00
Josua Frank
11f4cb8725 Merge branch 'louislam:master' into ntfy-bearer-authorization 2023-04-10 16:06:53 +02:00
Louis Lam
1bf97e701d Merge pull request #2837 from dsb3/hostname-regex
Feature: hostnames may be specified with a trailing dot
2023-04-09 16:27:16 +08:00
Louis Lam
4c1ac5e870 Merge pull request #2863 from mtelgkamp/ntfy-notification-improvements
Improve ntfy notifications
2023-04-09 16:08:12 +08:00
Louis Lam
9e320dc5fb Expose timezone and local datetime to notification providers 2023-04-09 16:01:27 +08:00
Louis Lam
2f3f929fbd Merge pull request #2831 from mtelgkamp/mattermost-notification-improvements
Improve mattermost notifications
2023-04-09 15:42:28 +08:00
Louis Lam
b776e88b26 Merge pull request #3042 from Zaid-maker/master
🐛 fix(package.json): correct typo in deploy-demo-server script name
2023-04-07 16:32:23 +08:00
Zaid-maker
49741bbef2 🐛 fix(package.json): correct typo in deploy-demo-server script name 2023-04-07 02:09:13 +05:00
Josua Frank
1f7f1f70bf Merge branch 'louislam:master' into ntfy-bearer-authorization 2023-04-06 10:55:28 +02:00
Louis Lam
be7d3f6142 Merge pull request #2752 from titanventura/show-tags-in-status-page-monitor-select-list
show tags in monitor select list under status page
2023-04-04 16:13:26 +08:00
Louis Lam
7706c29564 Minor 2023-04-04 15:42:37 +08:00
Louis Lam
9dd1b1ca0f Merge remote-tracking branch 'origin/master' into show-tags-in-status-page-monitor-select-list
# Conflicts:
#	src/pages/StatusPage.vue
2023-04-04 15:35:20 +08:00
Louis Lam
21ad715e6a Merge pull request #3021 from louislam/1.22.X
1.22.x -> master
2023-04-04 14:58:34 +08:00
Josua Frank
23af66f618 Merge branch 'louislam:master' into ntfy-bearer-authorization 2023-04-03 21:17:53 +02:00
Louis Lam
03aa685d3f Update to 1.21.2 2023-04-04 01:58:56 +08:00
Louis Lam
84c1baf706 Merge pull request #3015 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-04-04 00:09:45 +08:00
Weblate
23808efe2a Merge remote-tracking branch 'origin/master' 2023-04-03 16:07:13 +00:00
Marco
1db25a329f Translated using Weblate (German)
Currently translated at 100.0% (719 of 719 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
Ömer Faruk Genç
e314d517ad Translated using Weblate (Turkish)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
__filename
84d1cb73b6 Translated using Weblate (Korean)
Currently translated at 99.7% (717 of 719 strings)

Co-authored-by: __filename <filename@inft.kr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
Buchtič
ddd3d3bc92 Translated using Weblate (Czech)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Buchtič <martin.buchta@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
Alex Javadi
190e85d2c8 Translated using Weblate (Persian)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
MaxGremory
d8511fa201 Translated using Weblate (Spanish)
Currently translated at 99.0% (712 of 719 strings)

Co-authored-by: MaxGremory <holgaloper@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
rubesaca
e76d29dee5 Translated using Weblate (Spanish)
Currently translated at 99.0% (712 of 719 strings)

Co-authored-by: rubesaca <rubesaca@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:58 +00:00
MaxGremory
fb38048159 Translated using Weblate (Spanish)
Currently translated at 99.0% (712 of 719 strings)

Co-authored-by: MaxGremory <holgaloper@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:57 +00:00
Louis Lam
80f1959871 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 96.1% (691 of 719 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:57 +00:00
Ademaro
4ddc3b5f5e Translated using Weblate (Russian)
Currently translated at 100.0% (719 of 719 strings)

Co-authored-by: Ademaro <ademaro@ya.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:57 +00:00
Cyril59310
d173a3c663 Translated using Weblate (French)
Currently translated at 100.0% (719 of 719 strings)

Translated using Weblate (French)

Currently translated at 99.8% (718 of 719 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-04-03 16:06:57 +00:00
Louis Lam
45ef7b2f69 Fix Effective Date Range cannot be removed 2023-04-03 21:01:58 +08:00
Josua Frank
6b078b83bd Merge branch 'master' into ntfy-bearer-authorization 2023-04-03 08:33:05 +02:00
Louis Lam
22f730499f Improve the database connection string input 2023-04-03 02:57:14 +08:00
Louis Lam
1be74e2720 Merge pull request #2870 from chakflying/feat/auto-theme-status-page
Feat: Support auto theme in status pages
2023-04-03 02:38:30 +08:00
Louis Lam
32f84b5e4e Merge pull request #2491 from RubenNL/fix-metrics-push
Fixed the metrics for the push type.
2023-04-02 02:05:03 +08:00
Nelson Chan
97c7ad9cc7 Fix: Remove invalid gRPC url regex 2023-04-02 00:07:07 +08:00
Louis Lam
8f449ab738 Update to 1.21.2-beta.0 2023-04-01 16:36:51 +08:00
Louis Lam
dbfaddafca Validate cron before submit 2023-04-01 16:30:55 +08:00
Louis Lam
511038b45a Remove unused code 2023-04-01 04:22:10 +08:00
Louis Lam
e8d48561fc Change Retries from 0 to 1 2023-04-01 01:45:16 +08:00
Louis Lam
aeb2feacd3 Merge remote-tracking branch 'weblate/master'
# Conflicts:
#	src/lang/fr-FR.json
#	src/lang/tr-TR.json
2023-04-01 01:30:04 +08:00
DevMirza
c01055efb3 Translated using Weblate (Urdu)
Currently translated at 62.4% (445 of 713 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
2023-03-31 17:27:08 +00:00
Louis Lam
17ae47d091 Drop database backup logic, because duplicating a relative large database likely causes a disk space issue, users should take backup manually instead. 2023-04-01 00:58:23 +08:00
Louis Lam
de0d1edfd4 Merge pull request #2988 from chakflying/fix/socks-rejectUnauthorized
Fix: Pass rejectUnauthorized to Socks Proxy
2023-04-01 00:48:28 +08:00
Louis Lam
0f5a243450 Merge pull request #3003 from louislam/maintenance-fix
Maintenance Core Bug Fix & Improvements
2023-04-01 00:36:15 +08:00
Nelson Chan
b975c24531 UI: Improve design on mobile 2023-03-31 21:54:35 +08:00
Louis Lam
524cf7c607 WIP 2023-03-31 21:34:05 +08:00
Louis Lam
a6acd065bb WIP 2023-03-31 20:58:45 +08:00
Louis Lam
227cec86a8 WIP 2023-03-31 20:25:37 +08:00
Josua Frank
ba52e1c885 Merge branch 'louislam:master' into ntfy-bearer-authorization 2023-03-31 11:31:13 +02:00
Louis Lam
02291730fe WIP 2023-03-31 04:04:17 +08:00
Louis Lam
dcc065c86f Merge pull request #3001 from GrantBirki/master
:fishsticks: Upgrade json-yaml-validate
2023-03-30 20:33:58 +08:00
Grant Birkinbine
501dc29e6d use exclude file 2023-03-30 11:46:28 +01:00
Marco
d2b09ef042 Translated using Weblate (German)
Currently translated at 100.0% (713 of 713 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (713 of 713 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Ömer Faruk Genç
f608590526 Translated using Weblate (Turkish)
Currently translated at 100.0% (713 of 713 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Adam Stachowicz
a7f21bffec Translated using Weblate (Polish)
Currently translated at 100.0% (713 of 713 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Alex Javadi
ebd42444d1 Translated using Weblate (Persian)
Currently translated at 100.0% (713 of 713 strings)

Translated using Weblate (Persian)

Currently translated at 100.0% (713 of 713 strings)

Co-authored-by: Alex Javadi <15309978+aljvdi@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Mirinek
f0f7645c57 Translated using Weblate (Czech)
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Mirinek <mirek.nozicka77@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Louis Lam
3ada6fa99b Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 96.0% (681 of 709 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
401Unauthorized
4fb10a4e3f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: 401Unauthorized <hi@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Taha İPEK
1aac15bccc Translated using Weblate (Turkish)
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Taha İPEK <ti.tahaipek@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Alex
cbcd2a1027 Translated using Weblate (Russian)
Currently translated at 99.8% (708 of 709 strings)

Co-authored-by: Alex <proactivecam@inbox.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:27 +00:00
Cyril59310
17f038767d Translated using Weblate (French)
Currently translated at 100.0% (713 of 713 strings)

Translated using Weblate (French)

Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
Peter Petrík
edd1c6b662 Translated using Weblate (Slovak)
Currently translated at 27.2% (193 of 708 strings)

Co-authored-by: Peter Petrík <peter.petrik.fefe@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
ilya12077
29be8d3ddb Translated using Weblate (Russian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: ilya12077 <mr.ilya.1207@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
Alex
2ac1abd424 Translated using Weblate (Russian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Alex <proactivecam@inbox.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
DoyunShin
738a494dcb Translated using Weblate (Korean)
Currently translated at 97.7% (692 of 708 strings)

Co-authored-by: DoyunShin <doyun.shin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
AmadeusGraves
e575d41f7d Translated using Weblate (Spanish)
Currently translated at 99.2% (703 of 708 strings)

Co-authored-by: AmadeusGraves <angelfx19@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-03-28 18:55:26 +00:00
Nelson Chan
8ee4b844fd Fix: Pass rejectUnauthorized to Socks Proxy 2023-03-28 11:40:19 +08:00
Louis Lam
4ae437dd61 Update to 1.21.1 2023-03-27 20:09:24 +08:00
Louis Lam
6cb296b07a Update SQLite and Vue 2023-03-27 19:05:18 +08:00
Louis Lam
644c6a872f Merge pull request #2978 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-03-27 17:54:50 +08:00
Weblate
8c69c18f6d Merge remote-tracking branch 'origin/master' 2023-03-27 08:38:00 +00:00
Mirinek
c1a1160767 Translated using Weblate (Czech)
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Mirinek <mirek.nozicka77@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
Louis Lam
a0ebd88849 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 96.0% (681 of 709 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
401Unauthorized
2e9413cf33 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: 401Unauthorized <hi@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
Taha İPEK
278b52ec34 Translated using Weblate (Turkish)
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Taha İPEK <ti.tahaipek@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
Alex
caa757a27c Translated using Weblate (Russian)
Currently translated at 99.8% (708 of 709 strings)

Co-authored-by: Alex <proactivecam@inbox.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
Cyril59310
3ce117a943 Translated using Weblate (French)
Currently translated at 100.0% (709 of 709 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
Peter Petrík
cefe484b47 Translated using Weblate (Slovak)
Currently translated at 27.2% (193 of 708 strings)

Co-authored-by: Peter Petrík <peter.petrik.fefe@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:51 +00:00
ilya12077
a700892709 Translated using Weblate (Russian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: ilya12077 <mr.ilya.1207@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:50 +00:00
Alex
13d721ccf8 Translated using Weblate (Russian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Alex <proactivecam@inbox.ru>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:50 +00:00
DoyunShin
6c66bff518 Translated using Weblate (Korean)
Currently translated at 97.7% (692 of 708 strings)

Co-authored-by: DoyunShin <doyun.shin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:50 +00:00
AmadeusGraves
bea51d048b Translated using Weblate (Spanish)
Currently translated at 99.2% (703 of 708 strings)

Co-authored-by: AmadeusGraves <angelfx19@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-03-27 08:37:50 +00:00
Louis Lam
2e1a0fe4d5 Merge pull request #2983 from GrantBirki/master
GitHub Actions - Validate json / yaml files 📁
2023-03-27 16:36:20 +08:00
grantbirki
27b0895722 fix branch names 2023-03-26 22:35:00 +01:00
grantbirki
e687698851 add json / yaml validate job 2023-03-26 22:34:25 +01:00
Josua Frank
fc4312ca1a Merge branch 'master' into ntfy-bearer-authorization 2023-03-26 19:09:48 +02:00
Louis Lam
fbdeb30ce7 Merge pull request #2973 from chakflying/fix/limit-precision
Fix: Apply toPrecision as last step
2023-03-26 15:46:00 +08:00
Louis Lam
41bda4e1d7 Merge pull request #2975 from chakflying/fix/badge-no-label
Fix: Allow status badge with empty label
2023-03-26 15:42:12 +08:00
Louis Lam
4869e6531c Merge pull request #2980 from Genc/feature/twilio-notification-provider
Add Twilio Sms Notification Provider
2023-03-26 15:38:53 +08:00
Louis Lam
302b9cf644 Merge pull request #2956 from wwniclask25/feature/opsgenie-alerts
Feat: Add opsgenie notification provider
2023-03-26 15:36:50 +08:00
Louis Lam
3c3a192943 Merge pull request #2906 from chakflying/fix/duplicate-expiry-notif
Fix: Check for TLS expiry notified days smaller than target
2023-03-26 15:34:26 +08:00
Faruk Genç
b64c835cee Add Twilio Sms Notification Provider 2023-03-25 19:56:01 +03:00
Louis Lam
5266e713e6 Update ask-for-help.yaml 2023-03-25 23:06:51 +08:00
Louis Lam
86579d245f Update ask-for-help.yaml 2023-03-25 23:06:23 +08:00
Louis Lam
b6169408be Merge pull request #2962 from chakflying/fix/missing-clear-form
Fix: Add missing clearForm func.
2023-03-25 14:31:47 +08:00
Nelson Chan
4f05912276 Fix: Allow status badge with empty label 2023-03-25 02:44:15 +08:00
Nelson Chan
bf525371d9 Fix: Apply toPrecision as last step 2023-03-24 22:42:50 +08:00
Louis Lam
89bfc3bf33 Merge pull request #2908 from chakflying/chore/encrypted-private-key
Chore: Add support for encrypted SSL-key
2023-03-24 21:36:22 +08:00
Louis Lam
a2014278b8 Fix #2969 2023-03-24 19:16:12 +08:00
Louis Lam
70572af1af Fix #2969 2023-03-24 18:40:05 +08:00
Louis Lam
b31c23a43b Merge pull request #2970 from louislam/fix-2968
Fix crash issue caused by mysqlQuery()
2023-03-24 18:20:15 +08:00
Louis Lam
f4ee5271af Improve error handling of mysqlQuery and return row count as result 2023-03-24 16:24:00 +08:00
Louis Lam
7330db3563 Improve error handling of mysqlQuery and return row count as result 2023-03-24 16:08:30 +08:00
Louis Lam
097567e5f0 Merge pull request #2878 from chakflying/feat/status-page-countdown
Feat: Add status page countdown to refresh
2023-03-23 17:18:57 +08:00
Louis Lam
35f300c8eb Improve and reuse language keys 2023-03-23 17:17:53 +08:00
Nelson Chan
4c9d7ac8ca Fix: Add missing clearForm func. 2023-03-22 15:06:38 +08:00
Nelson Chan
ca52047bf5 Feat: Flush WAL on shutdown 2023-03-22 14:46:58 +08:00
niclas.koegl
d9558833fc Fix linting 2023-03-21 19:45:44 +01:00
niclas.koegl
776a482a1d Add Opsgenie notification provider 2023-03-21 19:29:37 +01:00
niclas.koegl
d2527d7254 Merge branch 'master' into feature/opsgenie-alerts 2023-03-21 18:10:10 +01:00
niclas.koegl
6dfca0c163 Add Opsgenie notification provider 2023-03-21 18:07:19 +01:00
Josua Frank
df47609671 Added default dropdown value 2023-03-21 13:55:51 +01:00
Josua Frank
e63f7562f8 linter fixes 2023-03-21 13:48:00 +01:00
Josua Frank
8921ed0cff fix indentation of language json files 2023-03-21 13:44:06 +01:00
Josua Frank
35a56dd9e0 Added dropdown for authentication methods 2023-03-21 13:40:24 +01:00
Josua Frank
442f54de84 Merge branch 'louislam:master' into ntfy-bearer-authorization 2023-03-21 13:01:49 +01:00
Louis Lam
72317633d9 Update to 1.21.0 2023-03-20 18:07:54 +08:00
Louis Lam
1973db28bf minor 2023-03-20 18:02:31 +08:00
Louis Lam
972ae60cfc Merge pull request #2913 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-03-20 18:01:42 +08:00
Weblate
56410afc3b Merge remote-tracking branch 'origin/master' 2023-03-20 09:57:54 +00:00
Alanimdeo
df975c2750 Translated using Weblate (Korean)
Currently translated at 97.1% (688 of 708 strings)

Co-authored-by: Alanimdeo <alan@imdeo.kr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Louis Lam
0cfd3fa642 Translated using Weblate (Georgian)
Currently translated at 1.5% (11 of 708 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ka/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Yoswaris Lawpaiboon
0b91391ced Translated using Weblate (Thai)
Currently translated at 81.3% (576 of 708 strings)

Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Bart Callant
02fde56aec Translated using Weblate (Dutch)
Currently translated at 94.7% (671 of 708 strings)

Co-authored-by: Bart Callant <bart@callant.net>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Mikolajek
da225a225f Translated using Weblate (French)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Mikolajek <weblate-1530@npk.pm>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Marco
a40c03f6f3 Translated using Weblate (German)
Currently translated at 100.0% (708 of 708 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Ghvinerias
c238508060 Translated using Weblate (Georgian)
Currently translated at 1.6% (12 of 708 strings)

Added translation using Weblate (Georgian)

Co-authored-by: Ghvinerias <Ghvinerias@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ka/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Tomasz Bielinski
abcbc3c55e Translated using Weblate (Slovak)
Currently translated at 11.7% (83 of 708 strings)

Added translation using Weblate (Slovak)

Co-authored-by: Tomasz Bielinski <tomasz@bielinski.sk>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
DoyunShin
350451edc8 Translated using Weblate (Korean)
Currently translated at 95.6% (677 of 708 strings)

Translated using Weblate (Korean)

Currently translated at 95.0% (673 of 708 strings)

Co-authored-by: DoyunShin <doyun.shin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:49 +00:00
Nelson Chan
b4b2ae55c0 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 95.6% (677 of 708 strings)

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
stanol
9ecb890f56 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Ömer Faruk Genç
4329fc6751 Translated using Weblate (Turkish)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Alexey
836e125256 Translated using Weblate (Russian)
Currently translated at 92.9% (658 of 708 strings)

Co-authored-by: Alexey <aosmirnov@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Donker_Jumala
0fe98de256 Translated using Weblate (Japanese)
Currently translated at 72.1% (511 of 708 strings)

Co-authored-by: Donker_Jumala <weareh0711@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Deathart
3825dd9f42 Translated using Weblate (French)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Deathart <deathart@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Cyril59310
c6cd0d9312 Translated using Weblate (French)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Michal
82975f8d7b Translated using Weblate (Czech)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
MrEddX
2ebbcc25a9 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-03-20 09:57:48 +00:00
Louis Lam
f2323b012b Deleted translation using Weblate (Chinese (Literary))
Deleted translation using Weblate (Mongolian)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
2023-03-20 09:57:48 +00:00
401Unauthorized
e5a6238cde chore: remove invalid template 2023-03-19 21:59:34 +08:00
Louis Lam
61506b1af2 [Deploy to demo] No need to restart demo-kuma 2023-03-15 15:06:53 +08:00
tombii
dbe73bd6ae Update monitor.js (#2929)
Language
2023-03-15 15:00:28 +08:00
Ghvinerias
0778549a6d Update i18n.js (#2927)
I want to commit to this project by translating it to Georgian,
I added "ge" : "ქართული", "ქართული" means Georgian in Georgian language
2023-03-15 14:57:47 +08:00
Louis Lam
09fa60de55 Merge pull request #2531 from doubles-ss/master
Feat: Add mtls authen option to http
2023-03-14 00:04:40 +08:00
Louis Lam
1e80365b73 Update node-ping to 0.4.4 2023-03-12 20:44:30 +08:00
Louis Lam
491239415e Merge remote-tracking branch 'origin/master' into doubles-ss_master
# Conflicts:
#	server/database.js
2023-03-12 18:38:19 +08:00
Lukas Bableck
cf59832d51 Set viewport-fit=cover in meta viewport tag 2023-03-10 17:42:30 +01:00
Lukas Bableck
8f259e1756 Add padding to bottom-nav 2023-03-10 17:42:06 +01:00
Yoswaris Lawpaiboon
29b2809279 Change Icon, Add missing var 2023-03-10 22:04:47 +07:00
Yoswaris Lawpaiboon
16f2701f61 idk how to fix camelcase lint 😢 2023-03-10 20:24:10 +07:00
Yoswaris Lawpaiboon
3bbf269da0 generator modal 2023-03-10 19:25:04 +07:00
Yoswaris Lawpaiboon
56d716cee4 Create badge-list.md 2023-03-10 17:46:45 +07:00
Louis Lam
0efabb4e39 Update to 1.21.0-beta.1 2023-03-10 16:16:00 +08:00
Louis Lam
b7aad4677d Merge pull request #2890 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations Update from Weblate
2023-03-10 16:04:12 +08:00
401Unauthorized
0a9ebf7fa4 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: 401Unauthorized <hi@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:36 +00:00
Michal
09aa7be4f5 Translated using Weblate (Czech)
Currently translated at 100.0% (708 of 708 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:36 +00:00
DevMirza
d3a3dcbde2 Translated using Weblate (Urdu)
Currently translated at 60.0% (423 of 704 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:36 +00:00
Louis Lam
7447a6570f Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 95.5% (673 of 704 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 95.5% (673 of 704 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:36 +00:00
Mathias
66e80aa6c3 Translated using Weblate (Estonian)
Currently translated at 42.0% (296 of 704 strings)

Co-authored-by: Mathias <mathias.talo@outlook.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/et/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Marco
f1c3604ab0 Translated using Weblate (German (Switzerland))
Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 90.6% (638 of 704 strings)

Co-authored-by: Marco <marco@nanoweb.ch>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Alexandr Loskutov
e8a81379bb Translated using Weblate (Ukrainian)
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: Alexandr Loskutov <alex_connor@icloud.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
ButterflyOfFire
1f13db26cc Translated using Weblate (Arabic)
Currently translated at 96.5% (680 of 704 strings)

Added translation using Weblate (Arabic)

Co-authored-by: ButterflyOfFire <butterflyoffire+uptimekuma@protonmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
stanol
1777270bb7 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: stanol <stanol777@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Ömer Faruk Genç
062191d61f Translated using Weblate (Turkish)
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Yoswaris Lawpaiboon
86e9c8ade9 Translated using Weblate (Thai)
Currently translated at 81.9% (577 of 704 strings)

Co-authored-by: Yoswaris Lawpaiboon <konglha19@outlook.co.th>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Adam Stachowicz
35cf31ced1 Translated using Weblate (Polish)
Currently translated at 99.0% (697 of 704 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Donker_Jumala
4608560b1d Translated using Weblate (Japanese)
Currently translated at 72.3% (509 of 704 strings)

Co-authored-by: Donker_Jumala <weareh0711@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
simonghpub
6a37a2a05b Translated using Weblate (Danish)
Currently translated at 79.4% (559 of 704 strings)

Co-authored-by: simonghpub <simonpmt@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2023-03-10 08:00:35 +00:00
Louis Lam
ba7af9b569 Uppercase and improve language keys 2023-03-10 15:55:39 +08:00
Louis Lam
6635412980 Merge pull request #2885 from cyril59310/master
Add keys for translation
2023-03-10 15:37:08 +08:00
Louis Lam
6e0aa109bc Uppercase and improve language keys 2023-03-10 15:36:23 +08:00
Louis Lam
533bc1505b Prevent generating duplicated timeslots 2023-03-09 22:03:23 +08:00
Nelson Chan
391692a708 Chore: Add support for encrypted SSL-key 2023-03-09 00:00:07 +08:00
Louis Lam
a599f5149b Merge pull request #2907 from chakflying/fix/disconnect-redis
Fix: Disconnect redis after ping
2023-03-08 22:57:30 +08:00
Nelson Chan
f32fcb204f Fix: Check for notified days smaller than target 2023-03-08 22:26:19 +08:00
Nelson Chan
230de63460 Fix: Disconnect redis after ping 2023-03-08 21:47:52 +08:00
Josua Frank
e8814e8479 added option for ntfy access tokens 2023-03-08 13:28:02 +00:00
Louis Lam
2dedc1cfbd Fix #2776 2023-03-07 20:48:11 +08:00
Louis Lam
65933de0cd Merge pull request #2886 from stanol/patch-1
Fix typo
2023-03-05 17:09:16 +08:00
Louis Lam
ce8eebc838 Fix #2880 2023-03-05 15:59:43 +08:00
stanol
ae5a683af8 Fix typo 2023-03-04 20:49:47 +02:00
cyril59310
70bb69fc73 add keys for translation 2023-03-04 15:17:20 +01:00
Cyril59310
2702335d91 Merge branch 'louislam:master' into master 2023-03-04 15:08:22 +01:00
Cyril59310
6de57f3283 Delete empty 2023-03-04 15:08:14 +01:00
Louis Lam
0dce492226 Update to 1.21.0-beta.0 2023-03-04 21:08:39 +08:00
Louis Lam
3e60912992 Update node-ping 2023-03-04 21:08:21 +08:00
Louis Lam
f17d23f5d8 A script for sorting contributors from weblate 2023-03-04 21:03:46 +08:00
Louis Lam
306cd37ec0 Merge pull request #2789 from Zaid-maker/patch-1
Add new Language: Urdu
2023-03-04 21:00:38 +08:00
Louis Lam
26dfa248c5 Merge pull request #2861 from byawitz/patch-1
Added Hebrew (he_IL) support
2023-03-04 20:59:48 +08:00
Louis Lam
993bdb3550 Merge pull request #2788 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations update from Uptime Kuma Weblate
2023-03-04 20:57:52 +08:00
Weblate
6335b72c2b Merge remote-tracking branch 'origin/master' 2023-03-04 12:41:24 +00:00
Louis Lam
7ec09d0118 Fix ipv6 issue for ping 2023-03-04 20:41:08 +08:00
Louis Lam
92c9b8bb63 Fix ipv6 issue for ping 2023-03-04 20:29:52 +08:00
Weblate
86a8ec27f3 Merge remote-tracking branch 'origin/master' 2023-03-04 11:12:28 +00:00
Louis Lam
010c7d681f Fix ipv6 issue for ping 2023-03-04 19:12:11 +08:00
Weblate
1d5246c34b Merge remote-tracking branch 'origin/master' 2023-03-04 09:35:23 +00:00
Louis Lam
8d1847c032 Merge pull request #2744 from bobby-ore/add-lunasea-user-id
Add ability to use User ID for LunaSea notifications
2023-03-04 17:35:15 +08:00
Weblate
13387cdd90 Merge remote-tracking branch 'origin/master' 2023-03-04 09:30:05 +00:00
Louis Lam
44077b38cb Merge pull request #2869 from chakflying/fix/clone-monitor-tags
Fix: assign tags when cloning monitor
2023-03-04 17:29:57 +08:00
Weblate
b60c11ff28 Merge remote-tracking branch 'origin/master' 2023-03-03 14:24:14 +00:00
Louis Lam
36aef2ae0d Merge pull request #2876 from chakflying/fix/uptime-for-push-beat
Fix: Clear uptime cache on push beat
2023-03-03 22:24:06 +08:00
Cyril59310
db5641c4bf Translated using Weblate (French)
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
ilya12077
901795729b Translated using Weblate (Russian)
Currently translated at 93.3% (657 of 704 strings)

Co-authored-by: ilya12077 <mr.ilya.1207@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
AnnAngela
7c1cca38dc Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
Oleg Logvinov
ce767d2350 Translated using Weblate (Russian)
Currently translated at 93.1% (656 of 704 strings)

Co-authored-by: Oleg Logvinov <oleglogwinow@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
401Unauthorized
b433a8fe5a Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: 401Unauthorized <hi@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
ilya12077
9fb190cc3c Translated using Weblate (Russian)
Currently translated at 93.1% (656 of 704 strings)

Translated using Weblate (Russian)

Currently translated at 92.1% (649 of 704 strings)

Co-authored-by: ilya12077 <mr.ilya.1207@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:56 +00:00
Justricity
917f406f30 Translated using Weblate (German)
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: Justricity <social@justricity.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
tim-wiegers
06ec7f2b61 Translated using Weblate (German)
Currently translated at 100.0% (704 of 704 strings)

Co-authored-by: tim-wiegers <hallobello17@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
DevMirza
6af1306b89 Translated using Weblate (Urdu)
Currently translated at 57.6% (400 of 694 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (694 of 694 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
fuyuki
7bbfb640ba Translated using Weblate (Japanese)
Currently translated at 56.6% (399 of 704 strings)

Translated using Weblate (Japanese)

Currently translated at 42.6% (300 of 704 strings)

Translated using Weblate (Japanese)

Currently translated at 40.3% (280 of 694 strings)

Co-authored-by: fuyuki <yuki627f@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Binyamin Yawitz
9758e1b71a Translated using Weblate (Hebrew (Israel))
Currently translated at 100.0% (694 of 694 strings)

Co-authored-by: Binyamin Yawitz <biny1000@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/he_IL/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Samuel PERRIER
eed49fed59 Translated using Weblate (French)
Currently translated at 100.0% (694 of 694 strings)

Co-authored-by: Samuel PERRIER <Samuel-Perrier@users.noreply.weblate.kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
401Unauthorized
1d7883208a Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (694 of 694 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Nelson Chan
5005c56e51 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 96.9% (673 of 694 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 91.0% (632 of 694 strings)

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Ömer Faruk Genç
cd61b28c85 Translated using Weblate (Turkish)
Currently translated at 100.0% (677 of 677 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Ivan Dmitriev
8b1affb9f4 Translated using Weblate (Russian)
Currently translated at 95.7% (648 of 677 strings)

Co-authored-by: Ivan Dmitriev <dmitriev.ivan.a@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
AnnAngela
a838432aef Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (674 of 674 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Furkan İ
1718890be7 Translated using Weblate (Turkish)
Currently translated at 100.0% (674 of 674 strings)

Co-authored-by: Furkan İ <developer@furkanipek.com.tr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Abin Abraham
efd4dece1b Translated using Weblate (Malayalam)
Currently translated at 3.7% (25 of 674 strings)

Added translation using Weblate (Malayalam)

Co-authored-by: Abin Abraham <iamabinabraham@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ml/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:55 +00:00
Cyril59310
c8a830047b Translated using Weblate (French)
Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (French)

Currently translated at 100.0% (674 of 674 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
Stian Meyer
db85f1758a Translated using Weblate (Norwegian Bokmål)
Currently translated at 40.2% (271 of 674 strings)

Co-authored-by: Stian Meyer <stian@smeyer.no>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nb_NO/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
401Unauthorized
f02e8be3e2 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.5% (670 of 673 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
AnnAngela
40cd5d41e3 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (669 of 669 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
Donker_Jumala
f2dc27c8fa Translated using Weblate (Japanese)
Currently translated at 40.8% (273 of 669 strings)

Co-authored-by: Donker_Jumala <weareh0711@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
401Unauthorized
2bb3b634c0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (669 of 669 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
Ömer Faruk Genç
3f3c5dca9f Translated using Weblate (Turkish)
Currently translated at 100.0% (669 of 669 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
Super Admin
482d2657ca Translated using Weblate (Yue)
Currently translated at 14.9% (100 of 667 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 94.1% (628 of 667 strings)

Co-authored-by: Super Admin <uptime@kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
MrEddX
fa2221781e Translated using Weblate (Bulgarian)
Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (694 of 694 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (667 of 667 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
victorpahuus
3e97563ee4 Translated using Weblate (Danish)
Currently translated at 72.0% (502 of 697 strings)

Co-authored-by: victorpahuus <dibbohh@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
Kurt S
68ea65bbd9 Translated using Weblate (German)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Kurt S <mail@kurtys.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:54 +00:00
DevMirza
6cea6dc001 Translated using Weblate (Urdu)
Currently translated at 56.6% (379 of 669 strings)

Translated using Weblate (Urdu)

Currently translated at 38.4% (268 of 697 strings)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Oleg Logvinov
a990dc89d8 Translated using Weblate (Russian)
Currently translated at 96.8% (675 of 697 strings)

Co-authored-by: Oleg Logvinov <oleglogwinow@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Louis Lam
16ce1f9ddf Translated using Weblate (Urdu)
Currently translated at 27.5% (192 of 697 strings)

Translated using Weblate (Hungarian)

Currently translated at 74.0% (516 of 697 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Zoe
2f5d9e7e46 Translated using Weblate (Norwegian Bokmål)
Currently translated at 41.1% (287 of 697 strings)

Co-authored-by: Zoe <me@s1lv3r.codes>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nb_NO/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
AmadeusGraves
f75ff2da98 Translated using Weblate (Spanish)
Currently translated at 98.9% (690 of 697 strings)

Co-authored-by: AmadeusGraves <angelfx19@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Lance
d1808fe9a3 Translated using Weblate (English)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Lance <2124757129@qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Zandor Smith
22577b88e9 Translated using Weblate (Dutch)
Currently translated at 99.7% (695 of 697 strings)

Translated using Weblate (Dutch)

Currently translated at 92.8% (647 of 697 strings)

Co-authored-by: Zandor Smith <info@zsinfo.nl>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Francesco Giuffré
61699bb238 Translated using Weblate (Italian)
Currently translated at 59.6% (416 of 697 strings)

Co-authored-by: Francesco Giuffré <ciccio.giuffre@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
krolli
8d31187a74 Translated using Weblate (Hungarian)
Currently translated at 74.0% (516 of 697 strings)

Co-authored-by: krolli <tuzoltoroli@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Michal
9a1301d0a9 Translated using Weblate (Czech)
Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (704 of 704 strings)

Translated using Weblate (Czech)

Currently translated at 99.7% (692 of 694 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (677 of 677 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (674 of 674 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (669 of 669 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (667 of 667 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Czech)

Currently translated at 99.8% (696 of 697 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
DevMirza
5f1b58e836 Translated using Weblate (Arabic (ar_SY))
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Urdu)

Currently translated at 27.6% (193 of 697 strings)

Translated using Weblate (Urdu)

Currently translated at 17.7% (124 of 697 strings)

Translated using Weblate (Hungarian)

Currently translated at 74.0% (516 of 697 strings)

Translated using Weblate (English)

Currently translated at 100.0% (697 of 697 strings)

Added translation using Weblate (Urdu)

Co-authored-by: DevMirza <pzhafeez@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar_SY/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ur/
Translation: Uptime Kuma/Uptime Kuma
2023-03-03 08:50:53 +00:00
Nelson Chan
193a273557 Feat: Add status page countdown to refresh 2023-03-03 08:25:41 +08:00
Nelson Chan
bc87abf5c2 Fix: Clear uptime cache on push beat 2023-03-03 05:57:36 +08:00
Nelson Chan
150607cc93 Feat: Support auto theme in status pages 2023-03-02 07:26:26 +08:00
Nelson Chan
ad26f0e817 Fix: assign tags when cloning monitor 2023-03-02 06:44:16 +08:00
Michael Telgkamp
cbbd3e20ad Codestyle: Add trailing comma 2023-03-01 23:05:23 +01:00
Nelson Chan
beb22f743d Chore: Update chart.js & improve perf. 2023-03-02 04:47:51 +08:00
Godwin Gabriel Ndlovu
6fc34e44d9 Resolved issue with using IP Address as GRPC URL
I've been having an issue with trying to use an IPAddress Host:Port combination in monitoring my GRPC instances. 
This was because the input type was set to url instead of text.
Even if the pattern passes the match test, the url would block as it requires a fully qualified domain name with HTTP and this would fail to submit
2023-03-01 19:45:31 +02:00
Louis Lam
94c3861608 Update Apprise to 1.3.0 2023-03-01 23:23:16 +08:00
Louis Lam
71c800b880 Merge remote-tracking branch 'origin/master' into notification-provider-pagertree
# Conflicts:
#	src/lang/en.json
2023-03-01 16:17:18 +08:00
Michael Telgkamp
7b4f90ce92 Improve ntfy notifications
- use tags `red_circle` for down and `green_circle` for up
- increase priority for down alert by 1 if not already max
- add monitor name and status to title
- use heartbeat msg as Message
- add monitor url as action
2023-03-01 08:37:06 +01:00
Binyamin Yawitz
0986457017 Added Hebrew (he_IL) support 2023-02-28 12:45:35 -05:00
Bobby Ore
b21c2adcc2 Rework lunasea notification to allow for device id and user id 2023-02-28 09:47:35 -06:00
Louis Lam
beafbf27ad Merge pull request #2858 from louislam/1.20.X
Merge 1.20.x to master
2023-02-28 18:13:15 +08:00
Louis Lam
958354e4db Minor 2023-02-28 16:58:36 +08:00
Louis Lam
38ab5e0f3e Merge pull request #2558 from Computroniks/feature/1685-prometheus-api-key
Added #1685: Add API keys for API authentication
2023-02-28 16:55:50 +08:00
Matthew Nickson
7e178d93df Moved location of disable expiry checkbox
Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-27 18:44:32 +00:00
Matthew Nickson
97e276bdb5 Fixed processing error with add API key
Also added padding below add button

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-27 18:19:56 +00:00
Louis Lam
fc8a324f41 [exe] single instance only 2023-02-27 18:52:19 +08:00
Louis Lam
bba8c6fe4e [exe] Open menu item is clickable after the server is ready 2023-02-27 18:48:11 +08:00
Louis Lam
fee8fd9320 [exe] Use Environment.CurrentDirectory instead of overriding fs 2023-02-27 18:45:54 +08:00
Matthew Nickson
669f8700b2 Switched to nanoid for key generation
To try and prevent any security issues, use an external package to
generate key instead of doing it ourselves. Note: we have to use nanoid
version 3 as nanoid version 4 requires ESM. Currently, nanoid v3 is
still supported.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-26 19:36:50 +00:00
Matthew Nickson
11fa690e09 Updated API Keys UI
The UI has now been moved to the settings page.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-26 18:07:57 +00:00
Matthew Nickson
06ee68dc0e Merge branch 'feature/1685-prometheus-api-key' of github.com:Computroniks/uptime-kuma into feature/1685-prometheus-api-key 2023-02-26 16:47:45 +00:00
Matthew Nickson
42a69c16ca Switched to crypto.randomBytes fpr key generation
Keys are now 32 bytes long encoded in a URL safe base64 string

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-26 16:47:34 +00:00
titanventura
db6b863445 show tags in monitor select list under status page : change select UI from normal select to vue-multiselect 2023-02-26 16:26:09 +05:30
Louis Lam
b91c526d2e [exe] Show server status 2023-02-26 17:56:01 +08:00
Louis Lam
5b0b743f81 Update to 1.20.2 2023-02-26 17:00:54 +08:00
Louis Lam
3c5f998191 Update mongodb to 4.14.0, possibly fix #2820 2023-02-26 03:23:02 +08:00
Louis Lam
a80f228136 Merge pull request #939 from jcvincenti/feature/482-add-description-to-monitor
Add description to monitor
2023-02-25 20:14:27 +08:00
Louis Lam
ea3b3abe36 Fine tune 2023-02-25 20:13:46 +08:00
Louis Lam
48c6f0578c Merge manually 2023-02-25 19:16:33 +08:00
Louis Lam
7f9332c753 Merge remote-tracking branch 'origin/master' into feature/482-add-description-to-monitor
# Conflicts:
#	server/database.js
#	server/model/monitor.js
#	src/icon.js
#	src/languages/en.js
#	src/languages/es-ES.js
2023-02-25 19:14:44 +08:00
Louis Lam
d668812df1 Fix merge issue 2023-02-25 17:59:25 +08:00
Louis Lam
f32d3af62c Merge remote-tracking branch 'origin/master' into doubles-ss_master
# Conflicts:
#	server/database.js
2023-02-25 17:57:25 +08:00
Louis Lam
8a115670cd Fix label and id
Co-authored-by: AlexKraus <alex.b.kraus@googlemail.com>
2023-02-25 17:55:40 +08:00
Louis Lam
a7b49fcd98 Fix json body after xml body added 2023-02-25 17:28:32 +08:00
Louis Lam
487eae71c7 Merge pull request #2489 from mathiash98/mathiash98/clone-monitor
Feature: Clone existing monitor
2023-02-25 17:10:56 +08:00
Louis Lam
4fed0c152e Show Copy of in front of the cloned monitor name 2023-02-25 17:05:03 +08:00
Louis Lam
43c797a34e Do not active the old monitor in the clone page 2023-02-25 16:20:59 +08:00
Louis Lam
f9a6d7ec44 Add a missing icon 2023-02-25 16:19:48 +08:00
Louis Lam
4a5a424198 Merge remote-tracking branch 'origin/master' into mathiash98/clone-monitor 2023-02-25 15:43:07 +08:00
Louis Lam
f47f2d5c87 Better save button for edit/add monitor page 2023-02-25 15:40:24 +08:00
Louis Lam
54cd7a0402 Merge manually 2023-02-25 15:08:39 +08:00
Louis Lam
f0ae67f89a Merge remote-tracking branch 'origin/master' into mathiash98/clone-monitor
# Conflicts:
#	src/languages/en.js
#	src/pages/EditMonitor.vue
2023-02-25 14:56:51 +08:00
Louis Lam
98bb854832 Merge pull request #2764 from chakflying/feat/add-new-tag
Feat: Add "Add New Tag" button in settings
2023-02-25 02:27:32 +08:00
Louis Lam
46894793fc Update Learn More url 2023-02-25 00:44:12 +08:00
Louis Lam
ef64077980 Merge remote-tracking branch 'origin/master' into feature/1685-prometheus-api-key
# Conflicts:
#	src/lang/en.json
2023-02-25 00:06:25 +08:00
Louis Lam
e873fea86d Merge pull request #2736 from blozano824/add-status-to-slack-notification
Adds name + status + message to Slack notification
2023-02-24 23:54:31 +08:00
Louis Lam
c4a9374671 Merge pull request #2835 from chakflying/fix/game-list-empty
Fix: getGameList returns nothing on first run
2023-02-24 23:34:47 +08:00
Nelson Chan
c65a920050 Chore: Fix code comment 2023-02-24 21:09:55 +08:00
Nelson Chan
7b8ed01f27 Fix: getGameList returns nothing on first run 2023-02-24 21:06:00 +08:00
Louis Lam
cecb0b6425 Merge pull request #2610 from bayramberkay/feature/add-xml-support-to-http-monitors
Add xml support to HTTP monitors
2023-02-24 17:26:47 +08:00
Louis Lam
8e3dd4202f Merge pull request #2595 from tminei/telegram_test
Added a more telegram notifications options
2023-02-24 17:22:43 +08:00
Louis Lam
af82ea742c Merge manually 2023-02-24 17:21:53 +08:00
Louis Lam
2fa233ae7f Fix prometheus null issues 2023-02-24 17:12:57 +08:00
Louis Lam
e9475ed3c0 Merge remote-tracking branch 'origin/master' into telegram_test
# Conflicts:
#	server/notification-providers/telegram.js
#	src/languages/en.js
2023-02-24 17:08:48 +08:00
Louis Lam
b923ba72ca Merge pull request #2334 from nlutsenko/nlutsenko.telegram_silentnotification
Add ability to send Telegram notifications silently, behind a setting.
2023-02-24 17:04:51 +08:00
Louis Lam
06278dc51f Fix telegram silent issue 2023-02-24 17:03:40 +08:00
Louis Lam
10228874fa Merge manually 2023-02-24 16:54:58 +08:00
Louis Lam
c5034c8f38 Merge remote-tracking branch 'origin/master' into nlutsenko.telegram_silentnotification
# Conflicts:
#	server/notification-providers/telegram.js
#	src/components/notifications/Telegram.vue
#	src/languages/en.js
2023-02-24 16:42:57 +08:00
Michael Telgkamp
186ca30508 Improve mattermost notifications 2023-02-23 17:40:39 +01:00
Ruben van Dijk
896e33815d Merge branch 'louislam:master' into fix-metrics-push 2023-02-23 14:11:39 +01:00
Louis Lam
7e3734af53 Better handling 2023-02-23 20:59:24 +08:00
Louis Lam
5789112f55 Merge remote-tracking branch 'origin/master' into feat-add-message-thread-id-telegram-nonfiction 2023-02-23 20:47:28 +08:00
Louis Lam
4dfc1a0221 Merge pull request #2664 from spali/keep_prometheus_instance
remember prometheus instance and expose it
2023-02-23 20:43:05 +08:00
Louis Lam
6235ce6b29 Merge pull request #2823 from chakflying/fix/footer-null
Fix: Add null check for injected HTML
2023-02-23 18:03:33 +08:00
Louis Lam
81a829bda7 Merge pull request #2812 from louislam/remove-translate-keys
Remove untranslatable keys and notification list optimization
2023-02-23 18:03:04 +08:00
Louis Lam
fa7f75a930 Organize notification list 2023-02-23 18:01:42 +08:00
Nelson Chan
7c8cff7708 Fix: Add null check for injected HTML 2023-02-23 17:02:16 +08:00
Austin Miller
5e1489a6ed PagerTree Notification - Send msg when heartbeatJSON null 2023-02-22 14:32:02 -07:00
Louis Lam
df5da0054e Remove more keys 2023-02-22 04:40:03 +08:00
Louis Lam
7da48b27a5 Fix getUniqueDefaultName 2023-02-22 04:29:43 +08:00
Louis Lam
de7df46aa8 Sort the notification list by name and remove translation keys of brand names or product names 2023-02-22 04:27:12 +08:00
Louis Lam
9ccaa4d120 Merge pull request #2786 from luckman212/luckman212-tagsort-1
sorted tags on dashboard
2023-02-22 01:11:03 +08:00
Louis Lam
42033c692f Merge pull request #2748 from chakflying/feat/improve-err-code
Feat: Use error message to detect and set status code
2023-02-22 01:01:53 +08:00
Louis Lam
aad1a7e0fa Merge pull request #2806 from andreasbrett/markdown_description
add markdown support for description
2023-02-21 16:19:14 +08:00
Louis Lam
2c62d197a0 [exe] Update dependencies 2023-02-21 16:03:41 +08:00
Louis Lam
dad21065cf Update release procedures 2023-02-21 15:45:18 +08:00
Louis Lam
02ddb58686 Fix cwd issues 2023-02-21 15:16:54 +08:00
Louis Lam
c061455475 Merge pull request #2191 from louislam/exe
Windows Executable File - uptime-kuma.exe
2023-02-21 03:23:07 +08:00
Louis Lam
0e38391454 Fix dpi issue using app.manifest 2023-02-21 03:11:29 +08:00
Louis Lam
22902139d2 Implement update 2023-02-21 02:50:25 +08:00
Louis Lam
4642f9be0a Fix download-dist.js do not exit sometimes 2023-02-20 23:15:49 +08:00
Andreas Brett
372c6b9078 add markdown support for description 2023-02-20 16:09:17 +01:00
Peace
0be8b111e2 chore: better up message
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-20 13:48:16 +01:00
Louis Lam
cf32b8bc64 Read latest version from website and add Run when system starts 2023-02-20 20:26:53 +08:00
Louis Lam
6a98ffe2f6 Merge remote-tracking branch 'origin/master' into exe
# Conflicts:
#	.dockerignore
#	.gitignore
2023-02-20 18:28:35 +08:00
Faruk Genç
72106ba4c4 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-02-18 22:38:40 +03:00
Faruk Genç
3ab0faee91 Add update query for old monitors and save new data correctly 2023-02-18 22:18:48 +03:00
Faruk Genç
9e3a77f419 Customize body placeholder for body encoding 2023-02-18 17:02:56 +03:00
Louis Lam
d1c43f432a Merge pull request #2747 from OidaTiftla/rename-consequently-to-consecutively
Rename "consequently" to "consecutively" as suggested by @skylarv
2023-02-18 16:53:45 +08:00
Louis Lam
ba3c7210ab Merge remote-tracking branch 'origin/master' into rename-consequently-to-consecutively
# Conflicts:
#	src/lang/cs-CZ.json
#	src/lang/de-DE.json
#	src/lang/en.json
#	src/lang/es-ES.json
#	src/lang/fr-FR.json
#	src/lang/id-ID.json
#	src/lang/pl.json
#	src/lang/pt-BR.json
#	src/lang/tr-TR.json
#	src/lang/zh-HK.json
2023-02-18 16:52:47 +08:00
cyril59310
3b74f5f359 empty 2023-02-17 19:50:18 +01:00
Faruk Genç
c9b4a7f53e Change column type 2023-02-17 17:59:43 +03:00
DevMirza
bd2c1d9c34 Add Urdu to right to left language array <3 2023-02-17 15:43:49 +05:00
Peace
cef0a0faf4 Merge branch 'master' into group-monitors 2023-02-16 21:38:53 +01:00
DevMirza
4df8db3f54 Add new Language: Urdu 2023-02-16 19:12:18 +05:00
Dave Baker
dfb95dfdcb Hostnames may be specified with a trailing dot to prevent DNS search lookups 2023-02-16 08:55:19 +00:00
Matthew Nickson
b8720b46c3 Switched to using Authorization header
Prometheus doesn't support using custom headers for exporters, however
it does support using the Authorisation header with basic auth. As
such, we switched from using X-API-Key to Authorization with the basic
scheme and an empty username field.

Also added a rate limit for API endpoints of 60 requests in a minute

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 21:53:49 +00:00
Matthew Nickson
1d4af39820 Fixed JSDoc for one method
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 19:31:22 +00:00
Luke Hamburg
dd1d71530f sorted tags on dashboard
see https://github.com/louislam/uptime-kuma/issues/2785
2023-02-15 14:06:29 -05:00
Matthew Nickson
01c71a0242 Fixed logic errors, removed dev leftovers
Fixed a logic error where a comma was used instead of an or, also
removed leftover console.logs from testing.

Date picker is now dissabled when don't expire is checked.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 11:15:15 +00:00
Matthew Nickson
d553c4c4f7 Added missing translation keys
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 00:53:42 +00:00
Matthew Nickson
e7feca1cd6 Added API key authentication handler
API key authentication is now possible by making use of the X-API-Key
header. API authentication will only be enabled when a user adds their
first API key, up until this point, they can still use their username
and password to authenticate with API endpoints. After the user adds
their first API key, they may only use API keys in future to
authenticate with the API.

In this commit, the prometheus /metrics endpoint has been changed over
to the new authentication system.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 00:39:29 +00:00
Matthew Nickson
cd796898d0 Added expiry check for frontend
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-14 22:41:06 +00:00
Matthew Nickson
05443f9bb7 Added language keys
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-14 22:16:41 +00:00
Matthew Nickson
d7f2fa982a Merge branch 'master' into feature/1685-prometheus-api-key 2023-02-14 19:53:33 +00:00
Matthew Nickson
ee2eb5109b Added basic web interface for API keys
Web interfaces for manging API keys have been added however translation
keys are still required.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-14 19:49:04 +00:00
Louis Lam
fdc3b2d57a Update to 1.20.1 2023-02-15 03:23:59 +08:00
Louis Lam
e04a8203dc Fix npm issue for deploy script 2023-02-15 03:20:40 +08:00
Louis Lam
2620ec3fae Merge pull request #2767 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations update from Uptime Kuma Weblate
2023-02-15 03:13:12 +08:00
Louis Lam
1877b90b3a Translated using Weblate (Finnish)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
Michal
609a61e600 Translated using Weblate (Czech)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
MrEddX
32ddff4e64 Translated using Weblate (Bulgarian)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
AmadeusGraves
11b45dd274 Translated using Weblate (Spanish)
Currently translated at 97.7% (681 of 697 strings)

Co-authored-by: AmadeusGraves <angelfx19@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
Jonne Saloranta
fb2f7179e9 Translated using Weblate (Finnish)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Jonne Saloranta <saloranta.jonne@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
eltionb
e3573ced65 Translated using Weblate (Albanian)
Currently translated at 3.2% (23 of 697 strings)

Added translation using Weblate (Albanian)

Co-authored-by: eltionb <eltion.it@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sq/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
Ömer Faruk Genç
8afc55db4e Translated using Weblate (Turkish)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
Luiz Felipe Arcos Campos
31fa074ffc Translated using Weblate (Portuguese (Brazil))
Currently translated at 38.8% (271 of 697 strings)

Co-authored-by: Luiz Felipe Arcos Campos <dino.bsb@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
Denys Konovalov
379d54e520 Translated using Weblate (German)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Denys Konovalov <privat@denyskon.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
victorpahuus
a518188e6f Translated using Weblate (Danish)
Currently translated at 62.9% (439 of 697 strings)

Co-authored-by: victorpahuus <dibbohh@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:52 +00:00
darkslash#2558
7d363ea146 Translated using Weblate (Japanese)
Currently translated at 28.1% (196 of 697 strings)

Added translation using Weblate (Chinese (Literary))

Added translation using Weblate (Mongolian)

Co-authored-by: darkslash#2558 <janisschelling@protonmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-02-14 19:08:51 +00:00
Louis Lam
d1175ff471 Fix #2777 2023-02-15 02:50:49 +08:00
Jonne Saloranta
aad087caac Added Finnish language translation (#2770)
* Added Finnish language translation

* Changed fi-FI to fi
2023-02-15 02:34:00 +08:00
Matthew Nickson
0d6a8b2101 Added more options for confirm modal
The ability to set the title of the modal has been added, as well as
custom callbacks for the no option.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-14 18:23:51 +00:00
Matthew Nickson
cd18b96f69 Added check to ensure backup exists when restoring (#2779)
A check to ensure that the backup database exists before deleting the
current database.

Fixes #2778

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-15 00:43:40 +08:00
Louis Lam
c19dcdba44 Add reminder to keep healthcheck.js 2023-02-14 12:31:29 +08:00
Nelson Chan
d9316f43ac Update README: Add npm as requirement (#2773) 2023-02-14 08:51:55 +08:00
Nelson Chan
33bb9f1ade Feat: Add simple validation on input 2023-02-14 07:16:18 +08:00
Louis Lam
6048bc5dfc Revert #2083's change of healthcheck.js 2023-02-14 00:46:22 +08:00
Louis Lam
5bf00fbe0b Fix deploy-demo-server.js do not download the dist 2023-02-13 17:40:25 +08:00
Louis Lam
76bdb62a5b Update to 1.20.0 2023-02-13 17:23:55 +08:00
Louis Lam
99eebf18b8 Merge pull request #2713 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations update from Uptime Kuma Weblate
2023-02-13 17:07:26 +08:00
Nelson Chan
1bcca60574 Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 93.9% (655 of 697 strings)

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:28 +00:00
aditya wahyudi
aeea1ff03f Translated using Weblate (Indonesian)
Currently translated at 83.3% (581 of 697 strings)

Co-authored-by: aditya wahyudi <aditbaco@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:28 +00:00
Jonne Saloranta
b49e3b65c1 Translated using Weblate (Finnish)
Currently translated at 15.2% (106 of 697 strings)

Added translation using Weblate (Finnish)

Co-authored-by: Jonne Saloranta <saloranta.jonne@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fi/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
hamx01
e9876986eb Translated using Weblate (Ukrainian)
Currently translated at 78.6% (548 of 697 strings)

Translated using Weblate (Russian)

Currently translated at 94.4% (658 of 697 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: hamx01 <asolianik2015@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Louis Lam
9268ad2f2c Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 82.0% (572 of 697 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Istratov Dmitrii
f1aa567a50 Translated using Weblate (Russian)
Currently translated at 86.6% (604 of 697 strings)

Co-authored-by: Istratov Dmitrii <funkill2@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Marchel Fahrezi
9d53db1504 Translated using Weblate (Indonesian)
Currently translated at 82.3% (574 of 697 strings)

Co-authored-by: Marchel Fahrezi <marchel.ace@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Asdrubal Duarte
a6f68a2e06 Translated using Weblate (Hungarian)
Currently translated at 58.8% (410 of 697 strings)

Translated using Weblate (Spanish)

Currently translated at 96.9% (676 of 697 strings)

Co-authored-by: Asdrubal Duarte <magyarlatin@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Super Admin
2ef98c1b10 Translated using Weblate (English)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Super Admin <uptime@kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Leonardo Lope
fea33a6475 Translated using Weblate (Portuguese (Portugal))
Currently translated at 63.2% (441 of 697 strings)

Co-authored-by: Leonardo Lope <tutoriaisleo3@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_PT/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Ferenc
3816c696cd Translated using Weblate (German)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Ferenc <ferenc.y@tutanota.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
René Dyhr
51860261e9 Translated using Weblate (Danish)
Currently translated at 50.6% (353 of 697 strings)

Co-authored-by: René Dyhr <bazzo39@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Julien Millau
d8a517e843 Translated using Weblate (French)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Julien Millau <mxjulien@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Marcos
971977b295 Translated using Weblate (Spanish)
Currently translated at 96.4% (672 of 697 strings)

Co-authored-by: Marcos <djoser.horus@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
AnnAngela
36c32c3636 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: AnnAngela <naganjue@vip.qq.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:27 +00:00
Ömer Faruk Genç
49396e2ccc Translated using Weblate (Turkish)
Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Tomasz Ad
90d6fbd20b Translated using Weblate (Polish)
Currently translated at 99.8% (696 of 697 strings)

Co-authored-by: Tomasz Ad <djtms84@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Alex Javadi
db918be126 Translated using Weblate (Persian)
Currently translated at 28.1% (196 of 697 strings)

Co-authored-by: Alex Javadi <dev@aljm.org>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Eduard Dev
5f71515253 Translated using Weblate (Romanian)
Currently translated at 80.3% (560 of 697 strings)

Translated using Weblate (English)

Currently translated at 100.0% (697 of 697 strings)

Co-authored-by: Eduard Dev <legocuedy09@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ro/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Jason Houk
bcac18cc2b Translated using Weblate (Japanese)
Currently translated at 25.2% (175 of 694 strings)

Co-authored-by: Jason Houk <dubsectordevelopment@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Cyril59310
06d1309d78 Translated using Weblate (French)
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (French)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (French)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (French)

Currently translated at 100.0% (694 of 694 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Rachatat Bunpat
fe66a24f00 Translated using Weblate (Thai)
Currently translated at 86.7% (601 of 693 strings)

Co-authored-by: Rachatat Bunpat <rbunpat@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
David F
cb563950e5 Translated using Weblate (Hebrew (Israel))
Currently translated at 99.8% (692 of 693 strings)

Co-authored-by: David F <me@thefourcraft.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/he_IL/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Dim
b9dd04ab05 Translated using Weblate (French)
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (French)

Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: Dim <DimitriDR@users.noreply.weblate.kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Andriy Skoropad
c70ccd1183 Translated using Weblate (Ukrainian)
Currently translated at 78.0% (541 of 693 strings)

Co-authored-by: Andriy Skoropad <scan4u@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Cyril59310
25d50e7660 Translated using Weblate (French)
Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
Savvas Mantzouranidis
050c388bc3 Translated using Weblate (Greek)
Currently translated at 99.8% (696 of 697 strings)

Translated using Weblate (Greek)

Currently translated at 99.4% (689 of 693 strings)

Co-authored-by: Savvas Mantzouranidis <mohito6@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/el/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:26 +00:00
401Unauthorized
34b1169ad6 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (694 of 694 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
UfukArt
6bda8d0b55 Translated using Weblate (Turkish)
Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: UfukArt <ufukatbas@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Nikita Ganzikov
0b9c5c70b2 Translated using Weblate (Russian)
Currently translated at 84.7% (587 of 693 strings)

Co-authored-by: Nikita Ganzikov <nganzikov@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Francesco Giuffré
73f85f4861 Translated using Weblate (Italian)
Currently translated at 60.3% (418 of 693 strings)

Translated using Weblate (Italian)

Currently translated at 55.4% (384 of 693 strings)

Co-authored-by: Francesco Giuffré <ciccio.giuffre@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Edoardo Ridolfi
48d89d8e61 Translated using Weblate (Italian)
Currently translated at 60.3% (418 of 693 strings)

Translated using Weblate (Italian)

Currently translated at 55.4% (384 of 693 strings)

Co-authored-by: Edoardo Ridolfi <edo2313@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
BlackScreen
727de9838b Translated using Weblate (German)
Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: BlackScreen <florian@barthold.tv>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Michal
a16ea4c6f3 Translated using Weblate (Czech)
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Czech)

Currently translated at 99.8% (696 of 697 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (694 of 694 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
MrEddX
46413a57e8 Translated using Weblate (Bulgarian)
Currently translated at 99.8% (696 of 697 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (694 of 694 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (693 of 693 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Adam Stachowicz
e10ea1049d Translated using Weblate (Polish)
Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (697 of 697 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (693 of 693 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Giuseppe Monaco
7984a52929 Translated using Weblate (Italian)
Currently translated at 53.1% (368 of 692 strings)

Co-authored-by: Giuseppe Monaco <GMonaco260@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Federico Lazcano
8f78c54ca2 Translated using Weblate (Spanish)
Currently translated at 96.8% (670 of 692 strings)

Co-authored-by: Federico Lazcano <federico.lazcano@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-02-13 08:59:25 +00:00
Louis Lam
c5ff010669 Add loose dependency qs which is used by aliyun-sms.js 2023-02-13 16:48:05 +08:00
Louis Lam
29976d8a03 minor 2023-02-13 16:35:12 +08:00
Louis Lam
f1bac7ce8a Add a script that deploy to the demo server 2023-02-13 16:26:45 +08:00
Nelson Chan
51dbb23230 Feat: Add "Add New Tag" button in settings 2023-02-13 05:05:30 +08:00
Louis Lam
8092640e20 Update security report guide (#2762) 2023-02-13 00:33:37 +08:00
Faruk Genç
19c8538149 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-02-11 23:56:38 +03:00
Louis Lam
c30e88ece2 Update dependencies 2023-02-10 17:52:46 +08:00
Louis Lam
cb953361b1 Update SECURITY.md 2023-02-10 17:46:44 +08:00
Louis Lam
c12b06348b Fix parsing issues of status page's og tags 2023-02-10 17:29:32 +08:00
Bobby Ore
48b637d4c8 Refactor to not introduce a breaking change 2023-02-09 08:49:19 -06:00
Nelson Chan
3439074835 Feat: Use message to improve errror status code 2023-02-09 17:42:02 +08:00
OidaTiftla
36d160ad02 Rename "consequently" to "consecutively" as suggested by @skylarv
https://github.com/louislam/uptime-kuma/pull/1212#issuecomment-1423373045
2023-02-09 09:04:47 +01:00
Bobby Ore
3a361d2621 lint fix 2023-02-08 14:16:02 -06:00
Bobby Ore
53d9e98e47 Added required to LunaSea notification type select field 2023-02-08 14:13:41 -06:00
Bobby Ore
8725e5daf9 Add ability to use User ID for LunaSea notifications 2023-02-08 14:08:25 -06:00
Brayan Lozano
d45aee450d Removes unecessary ternary operator 2023-02-07 22:34:10 -05:00
Brayan Lozano
727acb32bf Adds name + status + message to slack notification 2023-02-07 21:18:26 -05:00
Louis Lam
e241728419 Merge pull request #2729 from chakflying/patch-1
Fix [MySQL monitor]: Fix error when connection failed
2023-02-07 16:41:38 +08:00
Suriya Soutmun
43941fa2c6 feat: add mtls authen method in http/http keyword 2023-02-07 09:40:47 +07:00
Suriya Soutmun
faa78443d6 chore: alter table monitor add column tls_ca, tls_cert, tls_key for certificate data 2023-02-07 09:40:44 +07:00
Suriya Soutmun
ab3b2bddba [empty commit] pull request for http/http keyword mTLS authen 2023-02-07 09:37:55 +07:00
Nelson Chan
e1f956879d Fix: Use .destroy() instead of .end() 2023-02-07 05:01:53 +08:00
Austin Miller
1c0174c319 ESLint and verbiage changes 2023-02-06 13:07:56 -07:00
Austin Miller
ef54d9e3b6 Add PagerTree Notification Provider 2023-02-06 11:33:14 -07:00
Louis Lam
0197778af1 Fix change language issue in the setup page 2023-02-06 22:35:56 +08:00
Louis Lam
271cca0d23 Add Romanian in the dropdown 2023-02-06 15:21:45 +08:00
Faruk Genç
39c99b0ec4 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors
# Conflicts:
#	server/database.js
#	src/lang/en.json
2023-02-05 18:19:46 +03:00
Louis Lam
b6d7af988d Merge pull request #2718 from cyril59310/master
Add keys for translation
2023-02-05 12:04:55 +08:00
cyril59310
5fff63cd59 add keys for translation 2023-02-05 01:07:20 +01:00
Haytham Salama
c42e550382 style: formats 2023-02-04 23:46:19 +02:00
Haytham Salama
4323dee781 feat: add message thread id to lang 2023-02-04 22:54:19 +02:00
Haytham Salama
1bfb290718 feat: add message thread id for telegram nonfiction 2023-02-04 22:53:38 +02:00
Louis Lam
06dc61b343 Merge pull request #2567 from clcninja/feature-google-analytics
Feature - Added Optional Google Analytics tag for Status Page.
2023-02-04 17:58:18 +08:00
Louis Lam
afadfe32d5 Trim 2023-02-04 17:03:00 +08:00
Louis Lam
5f2affb38c Relocate and fix jsesc issue 2023-02-04 16:58:39 +08:00
Louis Lam
10c6f3b688 Merge remote-tracking branch 'origin/master' into feature-google-analytics 2023-02-04 15:40:13 +08:00
Faruk Genç
666838f334 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-02-04 00:03:05 +03:00
c
a823ed8ccc Feature - Google Analytics - Removed unused import. 2023-02-03 11:49:25 +00:00
Louis Lam
121ab82cc3 Merge pull request #2714 from Saibamen/auto_test_ignore_markdown
Do not run auto-test for markdown-only commits. Update versions
2023-02-03 17:41:17 +08:00
Adam Stachowicz
e0f0178644 Do not run auto-test for markdown-only commits. Update versions 2023-02-03 07:10:10 +01:00
Louis Lam
ec78d2a39b Update README.md 2023-02-03 13:39:45 +08:00
Louis Lam
ff09276de2 Update README.md 2023-02-03 13:38:14 +08:00
Louis Lam
e631db89b8 Update to 1.20.0-beta.0 2023-02-03 13:21:19 +08:00
Louis Lam
d39508a007 Change nightly version format 2023-02-03 13:19:51 +08:00
Louis Lam
b0673ba9ce Merge pull request #2570 from Computroniks/feature/#2365-allow-markdown-in-status-page-footer
Add support for markdown on status page
2023-02-03 12:36:50 +08:00
Joseph
2a6d98ff01 Feat: Expand and Simplify Badge Functionality (#2211)
* [expanding badges] added new configs

* [expanding badges] recieve ping in getPreviousHeartbeat()

* [expanding badges] re-added original new badges

* [expanding badges] recreate parity between old and new badges

* [expanding badges] fix linting
2023-02-03 12:33:48 +08:00
Louis Lam
f153082184 Drop en.js 2023-02-02 21:52:45 +00:00
c
913bb611d5 Feature - Google Analytics - Removed regex to validate a Google Analytics tag. 2023-02-02 21:52:45 +00:00
c
3afe8013ca Feature - Google Analytics - Change TEXT type to VARCHAR. 2023-02-02 21:52:45 +00:00
c
5a94a3fe3c Google Analytics - Moved string to updated file. 2023-02-02 21:52:44 +00:00
c
c08d8a5eaf Google Analytics - Simplified retrieving Tag ID from Status Page. 2023-02-02 21:51:03 +00:00
c
3ff0cbe311 Feature - Google Analytics - Simplified Module & Escaped the Script to prevent XXS. 2023-02-02 21:51:03 +00:00
c
fb2999706c Feature - Google Analytics - Added JSDoc to Google Analytics functions. 2023-02-02 21:51:03 +00:00
c
2b3a3895b3 Feature - Google Analytics - Use Regex to validate UA as per https://support.google.com/analytics/answer/9310895 2023-02-02 21:51:03 +00:00
c
99c0b8cb71 Feature - Google Analytics - Addressing PR Comments. 2023-02-02 21:51:03 +00:00
c
29e24e0de9 Feature - Added Optional Google Analytics tag for Status Page. 2023-02-02 21:51:03 +00:00
Matthew Nickson
3819266fa8 Fixed style of links in markdown
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-02-02 17:55:40 +00:00
Peace
e10ba9ed7e Merge branch 'master' into group-monitors 2023-02-02 17:59:48 +01:00
Faruk Genç
603b3a7fb6 Dummy commit for build 2023-02-02 19:50:29 +03:00
Faruk Genç
b2ddb5c9eb Dummy commit for build 2023-02-02 19:50:14 +03:00
Faruk Genç
4287f7e885 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors
# Conflicts:
#	src/lang/en.json
2023-02-02 19:43:17 +03:00
Louis Lam
d0ac3fc207 Merge pull request #2676 from UptimeKumaBot/weblate-uptime-kuma-uptime-kuma
Translations update from Uptime Kuma Weblate
2023-02-03 00:09:56 +08:00
오로라
2b1cb66ff7 Translated using Weblate (Korean)
Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: 오로라 <dhfhfk1203@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
mrkbaji
99d4b8ba50 Translated using Weblate (Hungarian)
Currently translated at 58.8% (407 of 692 strings)

Co-authored-by: mrkbaji <mrkbaji13@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
Dim
e1021ba38a Translated using Weblate (French)
Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Dim <DimitriDR@users.noreply.weblate.kuma.pet>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
rubesaca
c2ca60aaa2 Translated using Weblate (Spanish)
Currently translated at 94.6% (655 of 692 strings)

Translated using Weblate (Spanish)

Currently translated at 57.8% (400 of 692 strings)

Translated using Weblate (Spanish)

Currently translated at 56.6% (392 of 692 strings)

Translated using Weblate (Spanish)

Currently translated at 49.2% (341 of 692 strings)

Co-authored-by: rubesaca <rubesaca@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
Ömer Faruk Genç
30fb5f0b7b Translated using Weblate (Turkish)
Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
Louis Lam
a8af763f23 Translated using Weblate (Yue)
Currently translated at 14.3% (99 of 692 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
Michal
47dd7ef432 Translated using Weblate (Czech)
Currently translated at 100.0% (692 of 692 strings)

Translated using Weblate (Czech)

Currently translated at 99.8% (691 of 692 strings)

Co-authored-by: Michal <black23@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
MrEddX
3bc9c19e7f Translated using Weblate (Bulgarian)
Currently translated at 100.0% (692 of 692 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (692 of 692 strings)

Co-authored-by: MrEddX <mreddx@chatrix.one>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:50 +00:00
Nelson Chan
c1461fd01f Translated using Weblate (Chinese (Traditional, Hong Kong))
Currently translated at 82.8% (573 of 692 strings)

Translated using Weblate (Yue)

Currently translated at 2.6% (18 of 692 strings)

Translated using Weblate (Yue)

Currently translated at 2.1% (15 of 692 strings)

Co-authored-by: Nelson Chan <chakflying@hotmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
Cyril59310
1aaf251840 Translated using Weblate (French)
Currently translated at 98.6% (683 of 692 strings)

Translated using Weblate (French)

Currently translated at 98.6% (682 of 691 strings)

Co-authored-by: Cyril59310 <contact@cyril59310.fr>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
401Unauthorized
3208d98738 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (692 of 692 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (692 of 692 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (691 of 691 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.5% (681 of 691 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
Adam Stachowicz
fef09d3abd Translated using Weblate (Polish)
Currently translated at 100.0% (691 of 691 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (684 of 684 strings)

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
Louis Lam
1a601c9377 Translated using Weblate (Chinese (Traditional))
Currently translated at 97.2% (673 of 692 strings)

Translated using Weblate (English)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 62.7% (429 of 684 strings)

Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
Anonymous
15ec8db48c Translated using Weblate (English)
Currently translated at 100.0% (692 of 692 strings)

Translated using Weblate (Turkish)

Currently translated at 97.9% (670 of 684 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 58.6% (401 of 684 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma
2023-02-02 16:04:49 +00:00
Peace
9446c2d102 fix: use active instead of isActive in uploadBackup 2023-02-01 23:39:42 +01:00
Peace
2c581ade90 Merge branch 'louislam:master' into group-monitors 2023-02-01 20:44:09 +01:00
Peace
f286386f59 fix: add message for empty group pending state 2023-02-01 20:19:47 +01:00
Peace
9286dcb6ce fix: add serverside check against endless loops 2023-02-01 20:16:56 +01:00
Louis Lam
89465e6768 Update CONTRIBUTING.md 2023-02-01 22:39:09 +08:00
Louis Lam
683f446cf5 Add support for .env 2023-02-01 20:07:08 +08:00
Louis Lam
a8f0f1d872 Merge manually and remove to devDependencies 2023-02-01 15:51:33 +08:00
Louis Lam
f82d7b4007 Merge remote-tracking branch 'origin/master' into feature/#2365-allow-markdown-in-status-page-footer
# Conflicts:
#	package-lock.json
#	package.json
#	src/languages/en.js
2023-02-01 15:38:33 +08:00
Louis Lam
806eb799c1 Merge pull request #2647 from chakflying/fix/ip-regex
Fix: [Regex] Do not allow white space around IP
2023-02-01 15:24:03 +08:00
Louis Lam
c699868bb9 Merge pull request #2709 from chakflying/fix/use-constants
Chore: Use constants instead of int
2023-02-01 13:11:21 +08:00
Nelson Chan
95c934e08b Fix: Do not allow white space around IP
Feat: Trim input on submit

Test: Add test for whitespace regex match
2023-02-01 08:25:16 +08:00
Nelson Chan
348d0170fa Chore: Use constants instead of int 2023-02-01 05:33:36 +08:00
Faruk Genç
7dacc6a002 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-01-30 18:00:42 +03:00
Sebastian Kaempfe
a6894d36f2 [#2501] Dashboard: Details Page
- enable clickable URL on Dashboard Details if monitor is of type `mp-health`
2023-01-30 15:55:12 +01:00
Louis Lam
ce82ad1c12 Merge pull request #2083 from DevKyleS/patch-1
Bugfix: Fix healthcheck port value in healthcheck.js for Kubernetes support
2023-01-30 21:48:39 +08:00
Louis Lam
4fb43034cd Handle k8s in healthcheck.go 2023-01-30 21:46:27 +08:00
Louis Lam
18ae6fa6c1 Merge remote-tracking branch 'origin/master' into patch-1_k8s 2023-01-30 21:34:45 +08:00
Louis Lam
664da4a317 Merge pull request #2684 from gitstart/UPTM-3
Save button can't be found while edit and add in Mobile version
2023-01-30 21:20:39 +08:00
Faruk Genç
064bc00f46 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-01-30 13:09:16 +03:00
Louis Lam
fca0198d35 Merge pull request #2525 from chakflying/fix/maintenance-badge
Fix: Add support for pending & maintenance in badges
2023-01-30 15:32:28 +08:00
Louis Lam
6828d337ae Disable HTTP(s) - Browser Engine
Reason: Unfortunately, after some test, I found that Playwright requires a lot of libraries to be installed on the Linux host in order to start Chrome or Firefox. It will be hard to install, so I hide this feature for now.
2023-01-30 00:00:41 +08:00
Peace
66573934f6 refactor: remove old code 2023-01-28 15:21:17 +01:00
Peace
c444d78706 style: fix linting errors 2023-01-28 15:20:40 +01:00
Peace
661fa87134 feat: make parent link clickable 2023-01-28 14:53:40 +01:00
Peace
d48eb24046 docs: more comments 2023-01-28 14:28:53 +01:00
Peace
aee4c22dee perf: only do one filter instead of 3 in editMonitor 2023-01-28 14:28:34 +01:00
Peace
9a46b50989 docs: add comments 2023-01-28 14:22:15 +01:00
Peace
faf3488b1e fix: unfold tree if monitor is accessed directly 2023-01-28 14:15:25 +01:00
Peace
f3ac351d75 feat: set childs under maintenance if parent is too 2023-01-28 14:02:10 +01:00
Faruk Genç
35bd129d66 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-01-28 15:47:42 +03:00
Peace
aba515e172 feat: disable childs if parent is disabled 2023-01-28 13:39:17 +01:00
Louis Lam
ddce8f0cb0 Fix plugin installation 2023-01-28 19:00:13 +08:00
Louis Lam
1dc2546a39 Lint 2023-01-28 13:39:23 +08:00
Louis Lam
98f5bc51a8 Change golang version 2023-01-28 12:38:39 +08:00
Peace
97bd306a09 Merge branch 'louislam:master' into group-monitors 2023-01-28 03:07:42 +01:00
Peace
645fd94bba feat: add ability to group monitors in dashboard 2023-01-28 02:58:03 +01:00
Louis Lam
82f875beca Update README.md 2023-01-27 23:45:10 +08:00
Louis Lam
50573e6c89 Merge pull request #2635 from Computroniks/bug/2628-uptime-over-100
Perform sanity check on uptime for status page
2023-01-27 18:33:37 +08:00
Louis Lam
e5ca67d062 HTTPS Monitor using Real Browsers + Limited plugin support (#1787) 2023-01-27 18:25:57 +08:00
gitstart
54e63f3e25 Save button can't be found while edit and add in Mobile version 2023-01-26 12:47:33 +00:00
Faruk Genç
2673b509a5 Add "Body Encoding" to en.json 2023-01-25 20:22:50 +03:00
Faruk Genç
9329ec9234 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors
# Conflicts:
#	server/database.js
#	server/model/monitor.js
2023-01-25 20:20:11 +03:00
Louis Lam
d99d37898e Fix 2023-01-26 00:59:38 +08:00
UptimeKumaBot
dcda520d59 Translations update from Uptime Kuma Weblate (#2670)
* Update translation files

Updated by "Squash Git commits" hook in Weblate.

Translated using Weblate (Estonian)

Currently translated at 29.9% (205 of 685 strings)

Translated using Weblate (Spanish)

Currently translated at 29.7% (204 of 685 strings)

Translated using Weblate (Greek)

Currently translated at 84.6% (580 of 685 strings)

Translated using Weblate (German)

Currently translated at 94.1% (645 of 685 strings)

Translated using Weblate (German)

Currently translated at 94.2% (645 of 684 strings)

Translated using Weblate (German)

Currently translated at 94.2% (645 of 684 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 92.2% (632 of 685 strings)

Translated using Weblate (German (Switzerland))

Currently translated at 92.3% (632 of 684 strings)

Translated using Weblate (Danish)

Currently translated at 50.6% (347 of 685 strings)

Translated using Weblate (Danish)

Currently translated at 50.7% (347 of 684 strings)

Translated using Weblate (Czech)

Currently translated at 98.8% (677 of 685 strings)

Translated using Weblate (Arabic (ar_SY))

Currently translated at 96.3% (660 of 685 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (685 of 685 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Persian)

Currently translated at 29.7% (204 of 685 strings)

Translated using Weblate (Basque)

Currently translated at 77.9% (534 of 685 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 42.0% (288 of 685 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 42.1% (288 of 684 strings)

Translated using Weblate (Polish)

Currently translated at 99.8% (684 of 685 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (684 of 684 strings)

Translated using Weblate (Dutch)

Currently translated at 76.3% (523 of 685 strings)

Translated using Weblate (Dutch)

Currently translated at 76.4% (523 of 684 strings)

Translated using Weblate (Korean)

Currently translated at 76.4% (524 of 685 strings)

Translated using Weblate (Japanese)

Currently translated at 28.6% (196 of 685 strings)

Translated using Weblate (Italian)

Currently translated at 52.5% (360 of 685 strings)

Translated using Weblate (Italian)

Currently translated at 52.6% (360 of 684 strings)

Translated using Weblate (Indonesian)

Currently translated at 84.3% (578 of 685 strings)

Translated using Weblate (Hungarian)

Currently translated at 53.8% (369 of 685 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.8% (677 of 685 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 98.8% (677 of 685 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 40.8% (280 of 685 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 40.9% (280 of 684 strings)

Translated using Weblate (Croatian)

Currently translated at 83.5% (572 of 685 strings)

Translated using Weblate (Hebrew (Israel))

Currently translated at 96.7% (663 of 685 strings)

Translated using Weblate (Yue)

Currently translated at 57.9% (397 of 685 strings)

Translated using Weblate (Yue)

Currently translated at 57.9% (397 of 685 strings)

Translated using Weblate (Yue)

Currently translated at 9.4% (65 of 685 strings)

Translated using Weblate (Yue)

Currently translated at 9.4% (65 of 685 strings)

Translated using Weblate (Yue)

Currently translated at 2.0% (14 of 684 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 96.9% (664 of 685 strings)

Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 57.9% (397 of 685 strings)

Translated using Weblate (Vietnamese)

Currently translated at 67.4% (462 of 685 strings)

Translated using Weblate (Vietnamese)

Currently translated at 67.5% (462 of 684 strings)

Translated using Weblate (Ukrainian)

Currently translated at 74.8% (513 of 685 strings)

Translated using Weblate (Turkish)

Currently translated at 98.6% (676 of 685 strings)

Translated using Weblate (Thai)

Currently translated at 83.5% (572 of 685 strings)

Translated using Weblate (Swedish)

Currently translated at 15.7% (108 of 685 strings)

Translated using Weblate (Serbian)

Currently translated at 29.0% (199 of 685 strings)

Translated using Weblate (Serbian (latin))

Currently translated at 29.0% (199 of 685 strings)

Translated using Weblate (Serbian (latin))

Currently translated at 29.0% (199 of 685 strings)

Translated using Weblate (Slovenian)

Currently translated at 51.0% (350 of 685 strings)

Translated using Weblate (Russian)

Currently translated at 85.1% (583 of 685 strings)

Translated using Weblate (Portuguese (Portugal))

Currently translated at 29.0% (199 of 685 strings)

Translated using Weblate (French)

Currently translated at 98.9% (678 of 685 strings)

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Cyril59310 <contact@cyril59310.fr>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Victor Monteiro <victor@bbhost.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: cetteup <cetteup@dasemail.de>
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ar_SY/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/bg/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/da/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/de_CH/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/el/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/es/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/et/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/eu/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fa/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/he_IL/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/hu/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/id/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/it/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ja/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ko/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nb_NO/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/nl/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pl/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_BR/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/pt_PT/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sl/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sr_Latn/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/sv/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/th/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/uk/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/vi/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/
Translation: Uptime Kuma/Uptime Kuma

* Revert autofill mistake

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
Co-authored-by: Cyril59310 <contact@cyril59310.fr>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: MrEddX <mreddx@chatrix.one>
Co-authored-by: Victor Monteiro <victor@bbhost.com.br>
Co-authored-by: cetteup <cetteup@dasemail.de>
2023-01-26 00:55:59 +08:00
Louis Lam
8816be24d8 Merge pull request #1892 from Computroniks/feature/#1891-set-ping-packet-size
Added #1891: Set ping packet size
2023-01-25 16:16:43 +08:00
Louis Lam
e3828f09a3 Merge en.js to en.json 2023-01-25 16:13:09 +08:00
Louis Lam
5050ebc249 Merge remote-tracking branch 'origin/master' into feature/#1891-set-ping-packet-size
# Conflicts:
#	server/util-server.js
#	src/languages/en.js
2023-01-25 16:12:33 +08:00
UptimeKumaBot
82f33f4445 Translations update from Uptime Kuma Weblate (#2663)
* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.2% (677 of 682 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 56.4% (385 of 682 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (682 of 682 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (682 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 56.5% (386 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Translated using Weblate (Czech)

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Czech)

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 98.2% (671 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 56.8% (388 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Translated using Weblate (Czech)

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Russian)

Currently translated at 86.2% (589 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/ru/

* Translated using Weblate (Turkish)

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/tr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (683 of 683 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Added translation using Weblate (Aramaic)

* Added translation using Weblate (Yue)

* Translated using Weblate (Czech)

Currently translated at 100.0% (684 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/cs/

* Translated using Weblate (French)

Currently translated at 100.0% (684 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (684 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hans/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 57.6% (394 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Translated using Weblate (Yue)

Currently translated at 0.1% (1 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/

* Translated using Weblate (Chinese (Traditional, Hong Kong))

Currently translated at 58.6% (401 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/zh_Hant_HK/

* Translated using Weblate (English)

Currently translated at 100.0% (684 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/en/

* Translated using Weblate (Yue)

Currently translated at 2.0% (14 of 684 strings)

Translation: Uptime Kuma/Uptime Kuma
Translate-URL: https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/yue/

Co-authored-by: 401Unauthorized <yehowahliu@4o1.to>
Co-authored-by: Louis Lam <louislam@users.noreply.github.com>
Co-authored-by: test <tori@weblate2.louislam.net>
Co-authored-by: Buchtič <martin.buchta@gmail.com>
Co-authored-by: Michal <black23@gmail.com>
Co-authored-by: deluxghost <deluxghost@gmail.com>
Co-authored-by: Cyril59310 <archas.cyril@hotmail.fr>
Co-authored-by: sovushik <evgeniy@grachev.biz>
Co-authored-by: Ömer Faruk Genç <omer@farukgenc.com>
2023-01-25 02:00:56 +08:00
Louis Lam
a9b7bbcd9e Add 繁體中文 (廣東話 / 粵語) 2023-01-25 01:58:31 +08:00
Louis Lam
edd5592dca Update CONTRIBUTING.md 2023-01-25 01:37:19 +08:00
Louis Lam
e3246a2705 Update README.md 2023-01-25 01:30:58 +08:00
Louis Lam
e1e6227245 Update README.md 2023-01-25 01:29:29 +08:00
Louis Lam
b0e1bb4057 Create README.md 2023-01-25 01:28:10 +08:00
Louis Lam
2a86b43d69 Move notification related language keys to the bottom. 2023-01-25 01:10:25 +08:00
Louis Lam
1dabbd6442 Merge pull request #2666 from chakflying/fix/log-call
Fix: Fix incorrect log call format in docker monitor
2023-01-25 00:22:51 +08:00
Louis Lam
9cc3bd0de4 Avoid the multiple queries for Gamedig monitor 2023-01-25 00:19:54 +08:00
Nelson Chan
c4c720027c Fix: Use correct log call format 2023-01-24 23:47:33 +08:00
Louis Lam
3eab6e8238 Merge pull request #2566 from WhyKickAmooCow/master
Add GameDig monitor
2023-01-24 23:15:29 +08:00
Louis Lam
e637fa4e40 Add language key 2023-01-24 23:09:24 +08:00
Louis Lam
83e0401dd8 Show game list for GameDig monitor 2023-01-24 23:03:01 +08:00
Louis Lam
aab04f6644 Merge remote-tracking branch 'origin/master' into WhyKickAmooCow_master 2023-01-24 19:44:21 +08:00
Louis Lam
2408b1bffa Update README.md 2023-01-24 19:20:35 +08:00
Thomas Spalinger
f155ec9ba8 remember prometheus instance and expose it
in preperation for #2491,#680 and #898
2023-01-24 10:32:49 +00:00
Louis Lam
417efd9711 Update README.md 2023-01-24 18:13:31 +08:00
Faruk Genç
7866d1ec12 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors
# Conflicts:
#	src/languages/en.js
2023-01-24 12:49:12 +03:00
Louis Lam
bf5ac3fc19 Update CONTRIBUTING.md 2023-01-24 16:55:16 +08:00
Louis Lam
434bff6714 Add Help language key 2023-01-24 16:52:36 +08:00
Louis Lam
1d64b0c11b Merge pull request #2662 from YehowahLiu/weblate
Follow-up work of migrating to weblate
2023-01-24 16:36:15 +08:00
401Unauthorized
f125534829 remove WIP 2023-01-24 16:02:43 +08:00
401Unauthorized
ea83af3404 clean up codes 2023-01-24 16:00:51 +08:00
Louis Lam
b05c620ec2 Merge pull request #2611 from YehowahLiu/weblate
Prepare for using Weblate
2023-01-24 15:25:46 +08:00
401Unauthorized
9c4b03aee2 sync language changes from upstream 2023-01-24 15:18:30 +08:00
401Unauthorized
912686a299 Merge from upstream 2023-01-24 15:16:59 +08:00
Cyril59310
ae0ef79060 Update french translation (#2634) 2023-01-24 15:16:18 +08:00
Louis Lam
a2045b59bb Merge pull request #2638 from amworx/master
Arabic language support is now in action ✌️
2023-01-24 14:25:55 +08:00
Louis Lam
8ade7120ff Update src/i18n.js
Co-authored-by: 401Unauthorized <redme@live.cn>
2023-01-24 13:24:42 +08:00
Matthew Nickson
e9044ae956 Removed repetitiion of %
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-23 18:10:45 +00:00
Louis Lam
0c86a4d4e7 Merge pull request #2659 from Buchtic/master
Update cs-CZ.js
2023-01-24 00:13:17 +08:00
401Unauthorized
5683896910 docs: prepare for weblate 2023-01-23 21:06:58 +08:00
Buchtič
b288d71535 Update cs-CZ.js 2023-01-23 10:20:22 +01:00
Abdulrahman Mustafa
861ddc6117 Merge branch 'master' of https://github.com/amworx/uptime-kuma 2023-01-22 21:31:22 +00:00
Abdulrahman Mustafa
1197f881a1 Checked with eslint, with no errors 2023-01-22 21:31:02 +00:00
Abdulrahman Mustafa
211cbd4687 Merge branch 'louislam:master' into master 2023-01-22 23:28:24 +03:00
Faruk Genç
cd017fce98 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-01-22 02:22:59 +03:00
Louis Lam
dd6a76c4cc Merge pull request #2652 from Metatropics/main
Removed superflous 'Message' prefix from Pushover
2023-01-21 22:16:17 +08:00
alejandrohernandezrosales
fa23e7ad19 Removed superflous Message prefix 2023-01-20 23:59:11 -06:00
Faruk Genç
aef85078eb reorder fix 2023-01-20 12:29:56 +03:00
Faruk Genç
86ba6f829e Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors 2023-01-20 12:27:28 +03:00
Louis Lam
6ccf741bc4 Merge pull request #2632 from chakflying/fix/docker-timeout
Fix: Use default timeout & CachebleDnsHttpsAgent for docker monitor
2023-01-19 19:26:40 +08:00
Louis Lam
0a58069742 Merge pull request #2641 from louislam/1.19.X
Merge 1.19.6 to 1.20.X
2023-01-19 14:27:45 +08:00
Abdulrahman Mustafa
316599210d Arabic language support is now in action ✌️ 2023-01-18 19:03:04 +00:00
Matthew Nickson
86bcb85e9b Perform sanity check on uptime for status page
Fixes #2628
A sanity check is performed when calculating the uptime of a monitor on
status page. If it is greater than 100%, we just show 100%. This hasn't
been implemented on the dashboard at the request of @louislam due to
concerns it would make debugging more difficult in future if changes
were made to the uptime calculation.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-18 16:38:55 +00:00
Nelson Chan
6961b1bdd2 Fix: Use default timeout & CachebleDnsHttpsAgent 2023-01-18 09:53:04 +08:00
Louis Lam
54d4c4d3f7 Merge package-lock.json 2023-01-17 21:18:13 +08:00
Louis Lam
c47b6c5995 Merge remote-tracking branch 'origin/1.19.X'
# Conflicts:
#	package-lock.json
#	package.json
#	src/util-frontend.js
2023-01-17 21:17:04 +08:00
401Unauthorized
8128c8081b sync language file changes 2023-01-15 10:50:52 +08:00
401Unauthorized
e99652c5a2 sync language file changes 2023-01-15 10:46:29 +08:00
401Unauthorized
ceb7d48118 add convert script 2023-01-15 10:46:29 +08:00
401Unauthorized
bfa32f6b07 comment not allowed in json file 2023-01-15 10:46:29 +08:00
401Unauthorized
ae3a543b3b convert language files to json format 2023-01-15 10:46:29 +08:00
Louis Lam
1a9b013fc2 Merge pull request #2328 from rmarops/mongodb-ping
added MongoDB ping monitor
2023-01-15 01:43:43 +08:00
Louis Lam
1326761a8a Update mongodb and simplify the logic of mongodbPing 2023-01-15 01:36:49 +08:00
Louis Lam
e48a987b9c Merge remote-tracking branch 'origin/master' into mongodb-ping
# Conflicts:
#	server/model/monitor.js
#	server/util-server.js
#	src/pages/EditMonitor.vue
2023-01-15 01:13:11 +08:00
Faruk Genç
cf21aa3737 Fix lint 2023-01-14 16:51:07 +03:00
Faruk Genç
9890a0754b Fix lint 2023-01-14 16:48:26 +03:00
Faruk Genç
15c64d458b Fix lint 2023-01-14 16:48:12 +03:00
Faruk Genç
be850dd596 Merge remote-tracking branch 'remote/master' into feature/add-xml-support-to-http-monitors
# Conflicts:
#	server/database.js
#	server/model/monitor.js
#	src/languages/en.js
2023-01-14 16:40:13 +03:00
Faruk Genç
3adc9e65d6 Add only xml support to http monitors 2023-01-14 16:33:21 +03:00
Louis Lam
6437ef198f Merge pull request #2541 from long2ice/master
feat: support redis monitor
2023-01-14 20:16:53 +08:00
Louis Lam
973d5692d0 Merge pull request #2604 from black23/patch-1
Update cs-CZ.js
2023-01-14 13:04:41 +08:00
Louis Lam
468cb004d6 Merge pull request #1690 from chakflying/feat/tags-manager
Feat: Tags Manager
2023-01-13 23:29:01 +08:00
Louis Lam
f7d41a30fa Update src/components/TagEditDialog.vue
Co-authored-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-13 23:15:41 +08:00
black23
0ef686ac2f Update cs-CZ.js
new string
2023-01-13 14:52:03 +01:00
long2ice
3b5893ea60 fix: add preserve line in redisPingAsync 2023-01-13 21:30:10 +08:00
long2ice
21cd4d64c3 fix: redisPingAsync 2023-01-13 19:10:07 +08:00
long2ice
db757123ba refactor: reuse databaseConnectionString 2023-01-13 16:32:49 +08:00
Louis Lam
4dcf31621e Update README.md 2023-01-13 15:34:48 +08:00
Ruben
71f00b3690 Parse push ping parameter with parseInt. 2023-01-12 18:33:39 +01:00
shyneko
e427c70fef Translate fixes 2023-01-12 16:00:02 +02:00
shyneko
27e0b1eea1 Remove required attribute for optional field 2023-01-12 15:52:50 +02:00
Nelson Chan
9c1ba97e7d Chore: Fix typo 2023-01-12 21:25:33 +08:00
Nelson Chan
e9564619f1 Feat: Implement tags manager in settings
Fix: Remove unused color options

Chore: Fix typo
2023-01-12 21:25:33 +08:00
shyneko
521356e38a LINT fixes 2023-01-12 15:21:56 +02:00
shyneko
b91fe9d96d Added a more telegram options
such as thread id, silent notifications and forward protect
2023-01-12 15:09:05 +02:00
Sebastian Kaempfe
a21a47de93 [#2593] renamed the method sendCertNotification to better represent what id does. Evaluate certificate expiry from all certs in chain. Send a separate notification for every cert in chain, including cert type and CN. 2023-01-12 11:39:36 +01:00
Sebastian Kaempfe
f6d0f28b3a [#2593] during certificate evaluation also set the cert type for improved notifications 2023-01-12 11:34:37 +01:00
Nelson Chan
0ed3dd5e4f Fix: Add support for pending in badges 2023-01-12 04:14:46 +08:00
Nelson Chan
21b418230c Chore: reorder cases
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2023-01-10 19:25:31 +08:00
Matthew Nickson
66d5408aad Added DB schema for api keys
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-09 20:20:09 +00:00
Matthew Nickson
6e50784b6b Merge branch 'master' into feature/#2365-allow-markdown-in-status-page-footer 2023-01-09 20:03:11 +00:00
Matthew Nickson
80f2d6e2a7 Added markdown support for maintenance
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-08 20:54:16 +00:00
Matthew Nickson
852a088529 Added mardown support for incident
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-08 20:46:18 +00:00
Matthew Nickson
6bc0bd84af Allowed markdown in footer of status page
Markdown support has been added using the marked module. To secure
against XSS attacks, DOMPurify is used to sanitize the generated HTML
before it is loaded on the page.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-08 20:39:27 +00:00
Nelson Chan
dd82f36da3 Fix: Improve syntax & fix weird label logic 2023-01-09 00:16:18 +08:00
Adam Spurgeon
774d754b21 Add GameDig monitor 2023-01-08 21:43:30 +13:00
Matthew Nickson
fe03170540 [empty commit] pull request for #1685 Add API key for metrics page 2023-01-06 20:41:25 +00:00
Matthew Nickson
d6c91869af Reverted changes to en.js
Some changes were carried over in the merge

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-06 20:15:16 +00:00
Matthew Nickson
5d6770c0db Removed excess space around function
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-06 20:12:21 +00:00
Matthew Nickson
7a13b959a3 Updated to match changes in #2223
Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2023-01-06 20:09:40 +00:00
long2ice
40ebc2df79 feat: support redis monitor 2023-01-05 23:02:56 +08:00
Nelson Chan
942b55ca03 Fix: Add support for maintenance in badges 2023-01-03 21:45:55 +08:00
Mathias Haugsbø
239910a27c Change clone icon from plus to clone
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2023-01-02 13:17:38 +01:00
Ruben
9404efd86d Fixed the metrics for the push type. 2022-12-28 10:37:25 +01:00
Mathias Haugsbø
4d0bdae6bf Add jsdoc for Tag type
Does not work properly but is still useful
2022-12-27 23:27:23 +01:00
Mathias Haugsbø
608e3f5582 Feature: Clone existing monitor
Closes #565
Closes #2319

Adds the feature of cloning existing monitor, I have briefly tested it with ping and https and ensured that all properties was cloned including notifications.
2022-12-27 23:26:05 +01:00
Nikita Lutsenko
da16796ec4 Add ability to send Telegram notifications silently. 2022-12-03 23:10:56 -08:00
rmarops
0e30843a75 fixed lint check missing semicolon 2022-11-16 22:27:18 -05:00
rmarops
2103edb604 moved client close out of finally block and fixed linting errors 2022-11-16 22:21:15 -05:00
rmarops
b059a36e66 added MongoDB ping monitor 2022-11-16 20:50:34 -05:00
Matthew Nickson
4339ca7eb5 Merge branch 'master' into feature/#1891-set-ping-packet-size 2022-10-22 16:22:28 +01:00
Louis Lam
a487347b33 [exe] install dependencies and download dist 2022-10-09 03:47:06 +08:00
Louis Lam
655ba015a0 WIP 2022-10-08 23:47:27 +08:00
Louis Lam
3eaccb560e Implement Download Logic 2022-10-08 16:23:11 +08:00
Louis Lam
e741e7582d Merge remote-tracking branch 'origin/master' into exe 2022-10-07 20:43:53 +08:00
Louis Lam
4c45654780 WIP 2022-10-07 18:38:14 +08:00
Louis Lam
da778f05ac Update 2022-10-07 00:16:07 +08:00
Louis Lam
4a7e96f9ea Init C# Project for building exe 2022-10-06 12:08:10 +08:00
Justin Tisdale
f6919aef1d remove TODO 2022-09-26 17:10:56 -04:00
Justin Tisdale
6537f4fe74 content-type change 2022-09-26 17:09:10 -04:00
Justin Tisdale
5809088f27 Don't override a user-defined content-type header 2022-09-26 15:52:43 -04:00
Justin Tisdale
0814d643c1 Merge branch 'master' into feature/expand-http-payload-support 2022-09-25 10:45:32 -04:00
Kyle
7aa3f6c559 Corrected default hostname port for healthcheck 2022-09-14 15:04:21 -06:00
Kyle
db4b2cd984 Re-add support for UPTIME_KUMA_HOST and _PORT in healthcheck.js 2022-09-14 14:25:56 -06:00
Kyle
b4f0f8bca5 Replace healthcheck hostname env variable name 2022-09-13 22:18:00 -06:00
Kyle
b382064384 Replace port env var in healthcheck.js 2022-09-13 21:52:32 -06:00
Matthew Nickson
742b1337be Merge branch 'master' into feature/#1891-set-ping-packet-size 2022-09-10 21:20:03 +01:00
Justin Tisdale
fa1fc0fb05 Merge branch 'master' into feature/expand-http-payload-support 2022-09-07 11:34:58 -04:00
Justin Tisdale
6ec6410808 Merge branch 'master' into feature/expand-http-payload-support 2022-08-20 10:24:18 -04:00
Matthew Nickson
c3d655afb4 Merge branch 'master' into feature/#1891-set-ping-packet-size 2022-08-13 21:15:16 +02:00
Justin Tisdale
31cc328839 fix lint 2022-08-11 21:08:13 -04:00
Justin Tisdale
0d58526f25 Merge branch 'master' into feature/expand-http-payload-support 2022-08-11 21:04:11 -04:00
Justin Tisdale
2b9bf095a6 Add non-json support for http body 2022-08-11 20:57:03 -04:00
Justin Tisdale
3a18801722 Add Body Encoding field 2022-08-10 21:46:43 -04:00
Matthew Nickson
b5f04573f2 Added formatting to ping options
Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
2022-07-14 09:19:40 +01:00
Matthew Nickson
a54e58b4d6 Added Ping packet size #1891
This should fully implement #1891 by adding an extra field to the edit
monitor page and an extra column to the database. The user can now
set the size of the packet to send, it defaults to 56. A maximum limit
of 65500 was chosen to ensure that the total size of the packet does
not exceed the IPv4 maximum packet size and to comply with the limit
imposed by Windows.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
2022-07-14 08:32:51 +01:00
Matthew Nickson
219b00f660 [empty commit] pull request for #1891 set ping size 2022-07-13 23:08:35 +01:00
Juan Cruz Vincenti
fbf2df9e7a Add conditional rendering to description
* Modify Details component
* Modify MonitorList component
2021-12-14 19:11:32 -03:00
Juan Cruz Vincenti
934d633d4d Add description to monitor
* Add description to monitor model
* Add description field to database
* Add english and spanish translation for description
* Closes: #482
2021-12-14 19:11:32 -03:00
245 changed files with 36904 additions and 32873 deletions

View File

@@ -33,7 +33,7 @@ tsconfig.json
/ecosystem.config.js
/extra/healthcheck.exe
/extra/healthcheck
extra/exe-builder
### .gitignore content (commented rules are duplicated)
@@ -48,6 +48,4 @@ dist-ssr
#!/data/.gitkeep
#.vscode
### End of .gitignore content

View File

@@ -26,6 +26,12 @@ body:
label: "📝 Describe your problem"
description: "Please walk us through it step by step."
placeholder: "Describe what are you asking for..."
- type: textarea
id: error-msg
validations:
required: false
attributes:
label: "📝 Error Message(s) or Log"
- type: input
id: uptime-kuma-version
attributes:

View File

@@ -61,8 +61,8 @@ body:
id: operating-system
attributes:
label: "💻 Operating System and Arch"
description: "Which OS is your server/device running on?"
placeholder: "Ex. Ubuntu 20.04 x86"
description: "Which OS is your server/device running on? (For Replit, please do not report this bug)"
placeholder: "Ex. Ubuntu 20.04 x64 "
validations:
required: true
- type: input

19
.github/ISSUE_TEMPLATE/security.md vendored Normal file
View File

@@ -0,0 +1,19 @@
---
name: "Security Issue"
about: "Just for alerting @louislam, do not provide any details here"
title: "Security Issue"
ref: "main"
labels:
- security
---
DO NOT PROVIDE ANY DETAILS HERE. Please privately report to https://github.com/louislam/uptime-kuma/security/advisories/new.
Why need this issue? It is because GitHub Advisory do not send a notification to @louislam, it is a workaround to do so.
Your GitHub Advisory URL:

View File

@@ -16,7 +16,6 @@ Please delete any options that are not relevant.
- 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
- Other
- This change requires a documentation update

1
.github/config/exclude.txt vendored Normal file
View File

@@ -0,0 +1 @@
# This is a .gitignore style file for 'GrantBirki/json-yaml-validate' Action workflow

View File

@@ -6,8 +6,12 @@ name: Auto Test
on:
push:
branches: [ master ]
paths-ignore:
- '*.md'
pull_request:
branches: [ master ]
paths-ignore:
- '*.md'
jobs:
auto-test:
@@ -18,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
node: [ 14, 16, 18, 19 ]
node: [ 14, 16, 18, 20 ]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
@@ -36,6 +40,7 @@ jobs:
env:
HEADLESS_TEST: 1
JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }}
check-linters:
runs-on: ubuntu-latest

View File

@@ -1,4 +1,3 @@
name: Close Incorrect Issue
on:
@@ -12,13 +11,13 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node-version: [16.x]
node-version: [16]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

View File

@@ -0,0 +1,26 @@
name: json-yaml-validate
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
pull-requests: write # enable write permissions for pull request comments
jobs:
json-yaml-validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: json-yaml-validate
id: json-yaml-validate
uses: GrantBirki/json-yaml-validate@v1.3.0
with:
comment: "true" # enable comment mode
exclude_file: ".github/config/exclude.txt" # gitignore style file for exclusions

View File

@@ -3,13 +3,13 @@ on:
workflow_dispatch:
schedule:
- cron: '0 */6 * * *'
#Run every 6 hours
#Run every 6 hours
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
- uses: actions/stale@v7
with:
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.'

6
.gitignore vendored
View File

@@ -20,3 +20,9 @@ cypress/screenshots
/extra/healthcheck.exe
/extra/healthcheck
/extra/healthcheck-armv7
extra/exe-builder/bin
extra/exe-builder/obj
.vs
.vscode

View File

@@ -10,5 +10,6 @@
"color-function-notation": "legacy",
"shorthand-property-no-redundant-values": null,
"color-hex-length": null,
"declaration-block-no-redundant-longhand-properties": null
}
}

View File

@@ -17,8 +17,11 @@ The frontend code build into "dist" directory. The server (express.js) exposes t
## Directories
- config (dev config files)
- data (App data)
- db (Base database and migration scripts)
- dist (Frontend build)
- docker (Dockerfiles)
- extra (Extra useful scripts)
- public (Frontend resources for dev only)
- server (Server source code)
@@ -32,15 +35,18 @@ Yes or no, it depends on what you will try to do. Since I don't want to waste yo
Here are some references:
✅ Usually Accept:
- Bug/Security fix
- Translations
- Bug fix
- Security fix
- Adding notification providers
- Adding new language files (You should go to https://weblate.kuma.pet for existing languages)
- Adding new language keys: `$t("...")`
⚠️ Discussion First
- Large pull requests
- New features
❌ Won't Merge
- A dedicated pr for translating existing languages (You can now translate on https://weblate.kuma.pet)
- Do not pass auto test
- Any breaking changes
- Duplicated pull request
@@ -77,13 +83,13 @@ Before deep into coding, discussion first is preferred. Creating an empty pull r
## Project Styles
I personally do not like it when something requires so much learning and configuration before you can finally start the app.
I personally do not like something that requires so many configurations before you can finally start the app. I hope Uptime Kuma installation could be as easy as like installing a mobile app.
- Easy to install for non-Docker users, no native build dependency is needed (at least for x86_64), no extra config, no extra effort required to get it running
- Easy to install for non-Docker users, no native build dependency is needed (for x86_64/armv7/arm64), no extra config, no extra effort required to get it running
- Single container for Docker users, no very complex docker-compose file. Just map the volume and expose the port, then good to go
- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`.
- Settings should be configurable in the frontend. Environment variable is not encouraged, unless it is related to startup such as `DATA_DIR`
- Easy to use
- The web UI styling should be consistent and nice.
- The web UI styling should be consistent and nice
## Coding Styles
@@ -92,7 +98,7 @@ I personally do not like it when something requires so much learning and configu
- Follow ESLint
- Methods and functions should be documented with JSDoc
## Name convention
## Name Conventions
- Javascript/Typescript: camelCaseType
- SQLite: snake_case (Underscore)
@@ -106,7 +112,7 @@ I personally do not like it when something requires so much learning and configu
- IDE that supports ESLint and EditorConfig (I am using IntelliJ IDEA)
- A SQLite GUI tool (SQLite Expert Personal is suggested)
## Install dependencies
## Install Dependencies for Development
```bash
npm ci
@@ -124,6 +130,12 @@ Port `3000` and port `3001` will be used.
npm run dev
```
But sometimes, you would like to keep restart the server, but not the frontend, you can run these command in two terminals:
```
npm run start-frontend-dev
npm run start-server-dev
```
## Backend Server
It binds to `0.0.0.0:3001` by default.
@@ -139,12 +151,15 @@ express.js is used for:
### Structure in /server/
- jobs/ (Jobs that are running in another process)
- model/ (Object model, auto mapping to the database table name)
- modules/ (Modified 3rd-party modules)
- monitor_types (Monitor Types)
- notification-providers/ (individual notification logic)
- routers/ (Express Routers)
- socket-handler (Socket.io Handlers)
- server.js (Server entry point and main logic)
- server.js (Server entry point)
- uptime-kuma-server.js (UptimeKumaServer class, main logic should be here, but some still in `server.js`)
## Frontend Dev Server
@@ -195,18 +210,12 @@ Both frontend and backend share the same package.json. However, the frontend dep
### Update Dependencies
Install `ncu`
https://github.com/raineorshine/npm-check-updates
```bash
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.
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
If for maybe security reasons, a library must be updated. Then you must need to check if there are any breaking changes.
## Translations
Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
@@ -226,12 +235,13 @@ https://github.com/louislam/uptime-kuma/issues?q=sort%3Aupdated-desc
1. Draft a release note
2. Make sure the repo is cleared
3. If the healthcheck is updated, remember to re-compile it: `npm run build-docker-builder-go`
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
8. Deploy to the demo server: `npm run deploy-demo-server`
Checking:

View File

@@ -1,22 +1,23 @@
# Uptime Kuma
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a>
[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam)
[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) <a href="https://weblate.kuma.pet/projects/uptime-kuma/uptime-kuma/">
<img src="https://weblate.kuma.pet/widgets/uptime-kuma/-/svg-badge.svg" alt="Translation status" />
</a>
<div align="center" width="100%">
<img src="./public/icon.svg" width="128" alt="" />
</div>
It is a self-hosted monitoring tool like "Uptime Robot".
Uptime Kuma is an easy-to-use self-hosted monitoring tool.
<img src="https://uptime.kuma.pet/img/dark.jpg" width="700" alt="" />
<img src="https://user-images.githubusercontent.com/1336778/212262296-e6205815-ad62-488c-83ec-a5b0d0689f7c.jpg" width="700" alt="" />
## 🥔 Live Demo
Try it!
- Tokyo Demo Server: https://demo.uptime.kuma.pet (Sponsored by [Uptime Kuma Sponsors](https://github.com/louislam/uptime-kuma#%EF%B8%8F-sponsors))
- Europe Demo Server: https://demo.uptime-kuma.karimi.dev:27000 (Provided by [@mhkarimi1383](https://github.com/mhkarimi1383))
It is a temporary live demo, all data will be deleted after 10 minutes. Use the one that is closer to you, but I suggest that you should install and try it out for the best demo experience.
@@ -26,7 +27,7 @@ It is a temporary live demo, all data will be deleted after 10 minutes. Use the
* Fancy, Reactive, Fast UI/UX
* Notifications via Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and [90+ notification services, click here for the full list](https://github.com/louislam/uptime-kuma/tree/master/src/components/notifications)
* 20 second intervals
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/languages)
* [Multi Languages](https://github.com/louislam/uptime-kuma/tree/master/src/lang)
* Multiple status pages
* Map status pages to specific domains
* Ping chart
@@ -48,8 +49,13 @@ Uptime Kuma is now running on http://localhost:3001
### 💪🏻 Non-Docker
Required Tools:
- [Node.js](https://nodejs.org/en/download/) >= 14
Requirements:
- Platform
- ✅ Major Linux distros such as Debian, Ubuntu, CentOS, Fedora and ArchLinux etc.
- ✅ Windows 10 (x64), Windows Server 2012 R2 (x64) or higher
- ❌ Replit / Heroku
- [Node.js](https://nodejs.org/en/download/) 14 / 16 / 18 (20 is not supported)
- [npm](https://docs.npmjs.com/cli/) >= 7
- [Git](https://git-scm.com/downloads)
- [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background
@@ -85,6 +91,10 @@ pm2 monit
pm2 save && pm2 startup
```
### Windows Portable (x64)
https://github.com/louislam/uptime-kuma/releases/download/1.21.0/uptime-kuma-win64-portable-1.0.0.zip
### Advanced Installation
If you need more options or need to browse via a reverse proxy, please read:
@@ -142,17 +152,18 @@ Telegram Notification Sample:
If you love this project, please consider giving me a ⭐.
## 🗣️ Discussion
## 🗣️ Discussion / Ask for Help
### Issues Page
⚠️ For any general or technical questions, please don't send me an email, as I am unable to provide support in that manner. I will not response if you asked such questions.
You can discuss or ask for help in [issues](https://github.com/louislam/uptime-kuma/issues).
I recommend using Google, GitHub Issues, or Uptime Kuma's Subreddit for finding answers to your question. If you cannot find the information you need, feel free to ask:
### Subreddit
- [GitHub Issues](https://github.com/louislam/uptime-kuma/issues)
- [Subreddit r/Uptime kuma](https://www.reddit.com/r/UptimeKuma/)
My Reddit account: [u/louislamlam](https://reddit.com/u/louislamlam).
You can mention me if you ask a question on Reddit.
[r/Uptime kuma](https://www.reddit.com/r/UptimeKuma/)
## Contribute
@@ -171,7 +182,7 @@ Check out the latest beta release here: https://github.com/louislam/uptime-kuma/
If you want to report a bug or request a new feature, feel free to open a [new issue](https://github.com/louislam/uptime-kuma/issues).
### Translations
If you want to translate Uptime Kuma into your language, please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
If you want to translate Uptime Kuma into your language, please visit [Weblate Readme](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
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.

View File

@@ -2,10 +2,15 @@
## Reporting a Vulnerability
Please report security issues to https://github.com/louislam/uptime-kuma/security/advisories/new.
1. Please report security issues to https://github.com/louislam/uptime-kuma/security/advisories/new.
1. Please also create a empty security issues for alerting me, as GitHub Advisory do not send a notification, I probably will miss without this. https://github.com/louislam/uptime-kuma/issues/new?assignees=&labels=help&template=security.md
Do not use the public issue tracker or discuss it in the public as it will cause more damage.
## Do you accept other 3rd-party bug bounty platforms?
At this moment, I DO NOT accept other bug bounty platforms, because I am not familiar with these platforms and someone have tried to send a phishing link to me by this already. To minimize my own risk, please report through GitHub Advisories only. I will ignore all 3rd-party bug bounty platforms emails.
## Supported Versions
### Uptime Kuma Versions

View File

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 description TEXT default null;
COMMIT;

View File

@@ -0,0 +1,5 @@
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD game VARCHAR(255);
COMMIT

View File

@@ -0,0 +1,4 @@
-- 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 google_analytics_tag_id VARCHAR;
COMMIT;

View File

@@ -0,0 +1,6 @@
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD parent INTEGER REFERENCES [monitor] ([id]) ON DELETE SET NULL ON UPDATE CASCADE;
COMMIT

View File

@@ -0,0 +1,13 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
CREATE TABLE [api_key] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[key] VARCHAR(255) NOT NULL,
[name] VARCHAR(255) NOT NULL,
[user_id] INTEGER NOT NULL,
[created_date] DATETIME DEFAULT (DATETIME('now')) NOT NULL,
[active] BOOLEAN DEFAULT 1 NOT NULL,
[expires] DATETIME DEFAULT NULL,
CONSTRAINT FK_user FOREIGN KEY ([user_id]) REFERENCES [user]([id]) ON DELETE CASCADE ON UPDATE CASCADE
);
COMMIT;

View File

@@ -0,0 +1,12 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor ADD http_body_encoding VARCHAR(25);
COMMIT;
BEGIN TRANSACTION;
UPDATE monitor SET http_body_encoding = 'json' WHERE (type = 'http' or type = 'keyword') AND http_body_encoding IS NULL;
COMMIT;

View File

@@ -0,0 +1,11 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
DROP TABLE maintenance_timeslot;
-- 999 characters. https://stackoverflow.com/questions/46134830/maximum-length-for-cron-job
ALTER TABLE maintenance ADD cron TEXT;
ALTER TABLE maintenance ADD timezone VARCHAR(255);
ALTER TABLE maintenance ADD duration INTEGER;
COMMIT;

13
db/patch-monitor-tls.sql Normal file
View File

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

View File

@@ -0,0 +1,5 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor
ADD packet_size INTEGER DEFAULT 56 NOT NULL;
COMMIT;

View File

@@ -3,6 +3,6 @@ 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==1.2.1 && \
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 git && \
pip3 --no-cache-dir install apprise==1.4.0 && \
rm -rf /root/.cache

View File

@@ -2,7 +2,7 @@
# Build in Golang
# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck
############################################
FROM golang:1.19.4-buster
FROM golang:1.19-buster
WORKDIR /app
ARG TARGETPLATFORM
COPY ./extra/ ./extra/

View File

@@ -8,21 +8,21 @@ 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, 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==1.2.1 && \
RUN apt-get update && \
apt-get --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 git curl ca-certificates && \
pip3 --no-cache-dir install apprise==1.4.0 && \
rm -rf /var/lib/apt/lists/* && \
apt --yes autoremove
# 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 && \
RUN set -eux && \
mkdir -p --mode=0755 /usr/share/keyrings && \
curl --fail --show-error --silent --location --insecure https://pkg.cloudflare.com/cloudflare-main.gpg --output /usr/share/keyrings/cloudflare-main.gpg && \
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared buster main' | tee /etc/apt/sources.list.d/cloudflared.list && \
apt-get update && \
apt-get install --yes --no-install-recommends cloudflared && \
cloudflared version && \
rm -rf /var/lib/apt/lists/* && \
rm -f cloudflared.deb && \
apt --yes autoremove

View File

@@ -71,7 +71,7 @@ RUN npm ci
EXPOSE 3000 3001
VOLUME ["/app/data"]
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD extra/healthcheck
CMD ["npm", "run", "start-pr-test"]
############################################

View File

@@ -22,7 +22,8 @@ if (! exists) {
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
// Also update package-lock.json
childProcess.spawnSync("npm", [ "install" ]);
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
childProcess.spawnSync(npm, [ "install" ]);
commit(version);
tag(version);

View File

@@ -0,0 +1,60 @@
require("dotenv").config();
const { NodeSSH } = require("node-ssh");
const readline = require("readline");
const rl = readline.createInterface({ input: process.stdin,
output: process.stdout });
const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
(async () => {
try {
console.log("SSH to demo server");
const ssh = new NodeSSH();
await ssh.connect({
host: process.env.UPTIME_KUMA_DEMO_HOST,
port: process.env.UPTIME_KUMA_DEMO_PORT,
username: process.env.UPTIME_KUMA_DEMO_USERNAME,
privateKeyPath: process.env.UPTIME_KUMA_DEMO_PRIVATE_KEY_PATH
});
let cwd = process.env.UPTIME_KUMA_DEMO_CWD;
let result;
const version = await prompt("Enter Version: ");
result = await ssh.execCommand("git fetch --all", {
cwd,
});
console.log(result.stdout + result.stderr);
await prompt("Press any key to continue...");
result = await ssh.execCommand(`git checkout ${version} --force`, {
cwd,
});
console.log(result.stdout + result.stderr);
result = await ssh.execCommand("npm run download-dist", {
cwd,
});
console.log(result.stdout + result.stderr);
result = await ssh.execCommand("npm install --production", {
cwd,
});
console.log(result.stdout + result.stderr);
/*
result = await ssh.execCommand("pm2 restart 1", {
cwd,
});
console.log(result.stdout + result.stderr);*/
} catch (e) {
console.log(e);
} finally {
rl.close();
}
})();
// When done reading prompt, exit program
rl.on("close", () => process.exit(0));

View File

@@ -1,48 +0,0 @@
//
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");
/**
* Download specified file
* @param {string} url URL to request
*/
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

@@ -47,6 +47,7 @@ function download(url) {
});
}
console.log("Done");
process.exit(0);
});
tarStream.on("error", () => {

1
extra/exe-builder/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
packages/

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.Tracing" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.1" newVersion="4.1.1.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -0,0 +1,84 @@
using System.ComponentModel;
namespace UptimeKuma {
partial class DownloadForm {
/// <summary>
/// Required designer variable.
/// </summary>
private IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DownloadForm));
this.progressBar = new System.Windows.Forms.ProgressBar();
this.label = new System.Windows.Forms.Label();
this.labelData = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// progressBar
//
this.progressBar.Location = new System.Drawing.Point(12, 12);
this.progressBar.Name = "progressBar";
this.progressBar.Size = new System.Drawing.Size(472, 41);
this.progressBar.TabIndex = 0;
//
// label
//
this.label.Location = new System.Drawing.Point(12, 59);
this.label.Name = "label";
this.label.Size = new System.Drawing.Size(472, 23);
this.label.TabIndex = 1;
this.label.Text = "Preparing...";
//
// labelData
//
this.labelData.Location = new System.Drawing.Point(12, 82);
this.labelData.Name = "labelData";
this.labelData.Size = new System.Drawing.Size(472, 23);
this.labelData.TabIndex = 2;
//
// DownloadForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(496, 117);
this.Controls.Add(this.labelData);
this.Controls.Add(this.label);
this.Controls.Add(this.progressBar);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "DownloadForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Uptime Kuma";
this.Load += new System.EventHandler(this.DownloadForm_Load);
this.ResumeLayout(false);
}
private System.Windows.Forms.Label labelData;
private System.Windows.Forms.Label label;
private System.Windows.Forms.ProgressBar progressBar;
#endregion
}
}

View File

@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace UptimeKuma {
public partial class DownloadForm : Form {
private readonly Queue<DownloadItem> downloadQueue = new();
private readonly WebClient webClient = new();
private DownloadItem currentDownloadItem;
public DownloadForm() {
InitializeComponent();
}
private void DownloadForm_Load(object sender, EventArgs e) {
webClient.DownloadProgressChanged += DownloadProgressChanged;
webClient.DownloadFileCompleted += DownloadFileCompleted;
label.Text = "Reading latest version...";
// Read json from https://uptime.kuma.pet/version
var versionJson = new WebClient().DownloadString("https://uptime.kuma.pet/version");
var versionObj = JsonConvert.DeserializeObject<Version>(versionJson);
var nodeVersion = versionObj.nodejs;
var uptimeKumaVersion = versionObj.latest;
var hasUpdateFile = File.Exists("update");
if (!Directory.Exists("node")) {
downloadQueue.Enqueue(new DownloadItem {
URL = $"https://nodejs.org/dist/v{nodeVersion}/node-v{nodeVersion}-win-x64.zip",
Filename = "node.zip",
TargetFolder = "node"
});
}
if (!Directory.Exists("core") || hasUpdateFile) {
// It is update, rename the core folder to core.old
if (Directory.Exists("core")) {
// Remove the old core.old folder
if (Directory.Exists("core.old")) {
Directory.Delete("core.old", true);
}
Directory.Move("core", "core.old");
}
downloadQueue.Enqueue(new DownloadItem {
URL = $"https://github.com/louislam/uptime-kuma/archive/refs/tags/{uptimeKumaVersion}.zip",
Filename = "core.zip",
TargetFolder = "core"
});
File.WriteAllText("version.json", versionJson);
// Delete the update file
if (hasUpdateFile) {
File.Delete("update");
}
}
DownloadNextFile();
}
void DownloadNextFile() {
if (downloadQueue.Count > 0) {
var item = downloadQueue.Dequeue();
currentDownloadItem = item;
// Download if the zip file is not existing
if (!File.Exists(item.Filename)) {
label.Text = item.URL;
webClient.DownloadFileAsync(new Uri(item.URL), item.Filename);
} else {
progressBar.Value = 100;
label.Text = "Use local " + item.Filename;
DownloadFileCompleted(null, null);
}
} else {
npmSetup();
}
}
void npmSetup() {
labelData.Text = "";
var npm = "..\\node\\npm.cmd";
var cmd = $"{npm} ci --production & {npm} run download-dist & exit";
var startInfo = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = $"/k \"{cmd}\"",
RedirectStandardOutput = false,
RedirectStandardError = false,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = false,
WorkingDirectory = "core"
};
var process = new Process();
process.StartInfo = startInfo;
process.EnableRaisingEvents = true;
process.Exited += (_, e) => {
progressBar.Value = 100;
if (process.ExitCode == 0) {
Task.Delay(2000).ContinueWith(_ => {
Application.Restart();
});
label.Text = "Done";
} else {
label.Text = "Failed, exit code: " + process.ExitCode;
}
};
process.Start();
label.Text = "Installing dependencies and download dist files";
progressBar.Value = 50;
process.WaitForExit();
}
void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
progressBar.Value = e.ProgressPercentage;
var total = e.TotalBytesToReceive / 1024;
var current = e.BytesReceived / 1024;
if (total > 0) {
labelData.Text = $"{current}KB/{total}KB";
}
}
void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
Extract(currentDownloadItem);
DownloadNextFile();
}
void Extract(DownloadItem item) {
if (Directory.Exists(item.TargetFolder)) {
var dir = new DirectoryInfo(item.TargetFolder);
dir.Delete(true);
}
if (Directory.Exists("temp")) {
var dir = new DirectoryInfo("temp");
dir.Delete(true);
}
labelData.Text = $"Extracting {item.Filename}...";
ZipFile.ExtractToDirectory(item.Filename, "temp");
string[] dirList;
// Move to the correct level
dirList = Directory.GetDirectories("temp");
if (dirList.Length > 0) {
var dir = dirList[0];
// As sometime ExtractToDirectory is still locking the directory, loop until ok
while (true) {
try {
Directory.Move(dir, item.TargetFolder);
break;
} catch (Exception exception) {
Thread.Sleep(1000);
}
}
} else {
MessageBox.Show("Unexcepted Error: Cannot move extracted files, folder not found.");
}
labelData.Text = $"Extracted";
if (Directory.Exists("temp")) {
var dir = new DirectoryInfo("temp");
dir.Delete(true);
}
File.Delete(item.Filename);
}
}
public class DownloadItem {
public string URL { get; set; }
public string Filename { get; set; }
public string TargetFolder { get; set; }
}
}

View File

@@ -0,0 +1,377 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA
AABgAAAAAQAgAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA////BPT09Bfu7u4e8fHxJPPz8yv19fUy9fX1M/Pz8yvx8fEk9vb2HPPz8xXMzMwFAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//
/wHv7+8f7u7uPPPz81Tx8fFs8fHxgPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGB8fHxcfHx8V3x8fFI9PT0MOvr6w0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADy8vIU8fHxS/Dw8Hbx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fFr9PT0R/Dw8CIAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA8vLyFPHx8Vnx8fGB8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fFs9fX1Mb+/vwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAICAgALy8vI88fHxfvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvLy8nby8vI8gICAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAzMzMBfHx8Vrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyYf///wwAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwF8vLyYPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8W/z8/MWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv7+9R8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLw8PB26urqDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLy8ijx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgu7w7Ifj79ud2u7PtNLrw83P677dzeu85c3r
u+rM67rwzOu68c7rverQ68Dj0uvD3NbuyM3b7c+64u7apujv5ZPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxXgAAAAEAAAAAAAAAAAAAAAAAAAAA4+PjCfDw
8Hfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLd7tSmzeu92MbqsvvG6bH/xumy/8fq
s//H6rP/yOq0/8jqtf/J6rb/yeq2/8rrt//K67j/y+u4/8vruf/M67r/zOu7/83ru//Q7MDx1u7Kz9/t
163s8OuJ8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgu/v7y8AAAAAAAAAAAAA
AAAAAAAA7u7uPfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC5PDdl8jqtuTE6a7/xOmv/8Xp
sP/G6bH/xumx/8bpsv/H6rP/x+qz/8jqtP/I6rX/yeq2/8nqtv/K67f/yuu4/8vruP/L67n/zOu6/8zr
u//N67v/zey8/87svf/P67742e3Mx+jv5ZLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvDw
8HWAgIACAAAAAAAAAACqqqoD8vLyc/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLf7degxOiu+cPo
rf/D6a7/xOmu/8Xpr//F6bD/xumx/8bpsf/G6bL/x+qz/8fqs//I6rT/yOq1/8nqtv/J6rb/yuu3/8rr
uP/L67j/y+u5/8zruv/M67v/zeu7/83svP/O7L3/zuy9/87svfzc7tK28fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fEkAAAAAAAAAADz8/Mq8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgunv
5o3D6a/0wuis/8Lorf/D6K3/xOmu/8Tprv/F6a//xemw/8bpsf/G6bH/xumy/8fqs//H6rP/yOq0/8jq
tf/J6rb/yeq2/8rrt//K67j/y+u4/8vruf/M67r/zOu7/83ru//N7Lz/zuy9/87svf/O7L3/3e/TtPHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJNAAAAAAAAAADy8vJM8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgszqutDB6Kv/weir/8LorP/D6K3/w+it/8Tprv/E6a7/xemv/8XpsP/G6bH/xumx/8bp
sv/H6rP/x+qz/8jqtP/I6rX/yeq2/8nqtv/K67f/yuu4/8vruP/L67n/zOu6/8zru//N67v/zey8/87s
vf/O7L3/zuy++u3w6Yzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJ1AAAAAAAAAADx8fFr8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC6O/kjsDoqvzA6Kr/weir/8Loq//C6Kz/w+it/8Porf/E6a7/xOmu/8Xp
r//F6bD/xumx/8bpsf/G6bL/x+qz/8fqtP/I6rT/yOq1/8nqtv/J6rb/yuu3/8rruP/L67n/y+u5/8zr
uv/M67v/zeu7/83svP/O7L3/zuy9/93u07Xx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC////Bv//
/wfx8fGB8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC1ezJsr/nqf/A56n/weiq/8Hoq//C6Kv/wuis/8Po
rf/D6K3/xOmu/8Pprv+856T/uOed/7bmmv+05Zf/teWZ/7jnnf+86KP/wOio/8fqs//J6rb/yeq2/8rr
t//K67j/y+u5/8vruf/M67r/zOu7/83ru//N7Lz/zuy9/9buyNLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8vLyE/Ly8hPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCy+q6zr/nqP/A56n/wOep/8Ho
qv/B6Kv/wuir/8LorP+u5Y//neF2/5bgav+V4Gr/luBr/5fhbP+Y4W7/meFv/5rhcf+b4nL/nOJ0/53i
dv+j5H//reaM/7nnnf/E6q//y+y4/8vruf/L67n/zOu6/8zru//N67v/zey8/9Lsxd/x8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC7+/vIPb29hzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCx+m03L/n
qP+/56j/wOep/8Dnqf/B6Kr/weir/7nmn/+R32T/kt9l/5PfZ/+U4Gj/leBq/5bga/+X4W3/mOFu/5nh
b/+a4XH/m+Jy/5zidP+d4nX/nuN3/5/jeP+f4nn/weqq/8rruP/L67n/y+u5/8zruv/M67v/zeu7/9Ls
w+Lx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8PDwI/Hx8SXx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGCxeix5L/nqP+/56j/v+eo/8Dnqf/A56n/weiq/7Pllv+Q3mP/kd9k/5LfZf+T32f/lOBo/5Xg
av+W4Gv/l+Ft/5jhbv+Z4W//muFx/5vicv+c4nT/neJ1/57jd/+f43j/xOmu/8rrt//K67j/y+u5/8vr
uf/M67r/zOu7/9Tsxtfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC9PT0GO/v7yDx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGCx+m037/nqP+/56j/v+eo/7/nqP/A56n/wOip/7TmmP+P3mH/kN5j/5Hf
ZP+S32b/k99n/5TgaP+V4Gr/luBr/5fhbf+Y4W7/meFw/5rhcf+b4nL/nOJ0/53idf+h5Hz/yuu2/8nq
t//K67f/yuu4/8vruf/L67n/zOu6/9ftysrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC7e3tDvT0
9Bfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCyOq117/nqP+/56j/v+eo/7/nqP+/56j/wOep/7vn
of+O3mD/j95h/5DeY/+R32T/kt9m/5PfZ/+U4Gj/leBq/5bga/+X4W3/mOFu/5nhcP+a4nH/m+Jy/5zi
dP+r5Yr/yOq1/8nqtv/J6rf/yuu3/8rruP/L67n/y+u5/9zu1LHx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLz8/OA////A+7u7g/x8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCz+q+xb/nqP+/56j/v+eo/7/n
qP+/56j/v+eo/8Dnqf+S4Gb/jt5g/4/eYf+Q3mP/kd9k/5LfZv+T32f/lOBo/5Xgav+W4Gv/l+Ft/5jh
bv+Z4XD/muJx/5vic/+4553/yOq0/8jqtf/J6rb/yeq3/8rrt//K67j/y+u5/+bw4Zfx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fFrAAAAAP///wHz8/N88fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC1+zMrr/n
qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+f4Xn/jd5f/47eYP+P3mH/kN5j/5HfZP+S32b/k99n/5Tg
af+V4Gr/luBr/5fhbf+Y4W7/meFw/5vic//F6rD/x+q0/8jqtP/I6rX/yeq2/8nqt//K67f/zOu88u/x
74Px8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLv7+9QAAAAAAAAAADw8PBm8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC5e7gk7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+u5I//jN1d/43eX/+O3mD/j95h/5De
Y/+R32T/kt9m/5PfZ/+U4Gn/leBq/5bga/+X4W3/mOFu/6rliP/G6rL/x+qz/8fqtP/I6rT/yOq1/8nq
tv/J6rf/1OzGy/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YL19fUzAAAAAAAAAADy8vJO8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgsPoru2/56j/v+eo/7/nqP+/56j/v+eo/7/nqP++6Kf/j95i/4zd
Xf+N3l//jt5g/4/eYv+Q3mP/kd9k/5LfZv+T32f/lOBp/5Xgav+W4Gz/l+Ft/7voov/G6bL/xuqy/8fq
s//H6rT/yOq1/8jqtf/J6rb/4e/Zo/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLw8PARAAAAAAAA
AADu7u4u8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgszpvMm/56j/v+eo/7/nqP+/56j/v+eo/7/n
qP+/56j/q+SL/4vdXP+M3V3/jd5f/47eYP+P3mL/kN9j/5HfZP+S32b/k99n/5Tgaf+V4Gr/qOOH/8Xp
sP/G6bH/xumy/8bqsv/H6rP/x+q0/8jqtf/K67jy8PHwhPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8WoAAAAAAAAAAAAAAADo6OgL8fHxgfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxguDv2J2/56j/v+eo/7/n
qP+/56j/v+eo/7/nqP+/56j/v+eo/6Xjgv+L3Vz/jN1d/43eX/+O3mD/j95i/5DfY/+R32T/kt9m/5Pf
Z/+k44D/xOmu/8XpsP/F6bD/xumx/8bpsv/G6rL/x+qz/8fqtP/W7cnB8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvPz80AAAAAAAAAAAAAAAAAAAAAA8PDwZ/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLD6K/rv+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+u5I//kt5n/4zdXf+N3l//jt5g/4/e
Yv+Q32P/luFs/67kj//D6K3/xOmu/8Tpr//F6bD/xemw/8bpsf/G6bL/xuqy/8fqtP7o7+WR8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8xYAAAAAAAAAAAAAAAAAAAAA8vLyPPHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLV7ci0v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/wOio/7Xl
mv+u5I7/rOSM/67kj/+35pz/wumr/8Lorf/D6K3/w+it/8Tprv/E6a//xemw/8XpsP/G6bH/xumy/9Ds
wNPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyZQAAAAAAAAAAAAAAAAAAAAAAAAAA////DPHx
8YDx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCx+m03L/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/n
qP+/56j/v+eo/7/nqP+/56j/wOep/8Doqv/B6Kr/weir/8LorP/C6K3/w+it/8Porv/E6a7/xOmv/8Xp
sP/F6bD/yOq18uvw6Yvx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC7+/vMQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAPHx8Vzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC6O/ij8LorPG/56j/v+eo/7/n
qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/8Dnqf/A6Kr/weiq/8Hoq//C6Kz/wuit/8Po
rf/D6K7/xOmu/8Tpr//F6bH74u/anvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLw8PB6////BQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPz8yrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxguHu
2pnB56v2v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP/A56n/wOiq/8Ho
q//B6Kv/wuis/8Lorf/D6K3/w+mu/8Tprv3b7dKq8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fFJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHy8vJf8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLi7tyXwumt8L/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/n
qP+/56j/wOep/8Doqv/B6Kv/weir/8LorP/C6K3/xOiv+d7u1aTx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvLy8nb///8KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv7+8Q8/Pze/Hx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC6/Dpiszqu82/56j/v+eo/7/nqP+/56j/v+eo/7/n
qP+/56j/v+eo/7/nqP+/56j/v+eo/8Dnqf/A6Kr/weir/8Hoq//H6bTj5e7elfHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8yoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9fX1MvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLe7tShx+mz3r/n
qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP/A56n/xumy5drtz6rv8e+D8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPHx8Unx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgubv45DU68e2y+q6z8XoseTD6a7uweir9MPpru7F6bHly+q50tLsxLrl796U8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJh////AwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wHx8fFZ8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8Wzf398IAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8D8/PzVfHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8PDwZujo
6AsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA////AfHx8Ujx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fFa////BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADz8/Mp8vLydvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8/PzfPHx8TcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CvLy8lDz8/N/8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvPz84Hx8fFa8PDwEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADw8PAR8vLyTvHx8X3x8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fF/8/PzVvT09BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wXz8/Mq8/PzU/Hx8XDx8fGB8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLy8vJz8fHxWO/v7y////8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G7e3tHfLy
8ifu7u4u8PDwNPT09C/y8vIo7+/vH+Pj4wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP///////wAA////////AAD///////8AAP//gAf//wAA//gAAD//AAD/wAAAB/8AAP+A
AAAB/wAA/gAAAAB/AAD8AAAAAD8AAPgAAAAAHwAA8AAAAAAPAADwAAAAAAcAAOAAAAAABwAA4AAAAAAD
AADAAAAAAAMAAMAAAAAAAwAAwAAAAAABAACAAAAAAAEAAIAAAAAAAQAAgAAAAAABAACAAAAAAAEAAIAA
AAAAAQAAgAAAAAABAACAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAABwAAwAAAAAAH
AADgAAAAAAcAAOAAAAAADwAA4AAAAAAPAADwAAAAAB8AAPAAAAAAHwAA+AAAAAA/AAD8AAAAAD8AAPwA
AAAAfwAA/gAAAAD/AAD/AAAAAf8AAP+AAAAD/wAA/8AAAAf/AAD/8AAAH/8AAP/8AAA//wAA//8AAf//
AAD//+AP//8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAgICAAu/v7xD09PQX7u7uHvDw8CP29vYb8vLyFOrq6gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICA
gALy8vIm7+/vT/Pz82fz8/N98fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvDw8Hrw8PBm7+/vUPT0
9C3o6OgLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOPj
4wnz8/NC8vLydPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YHy8vJj8/PzKoCAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADx8fEl8vLydfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxcfHx8SUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA9PT0LfHx8YDx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8/PzgPLy8j0AAAABAAAAAAAA
AAAAAAAAAAAAAO3t7Rzx8fGA8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLr8OmM5O7emeTv
3Z7h79mj5fDem+nv45Tu8u6H8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvLy
8joAAAAAAAAAAAAAAAD///8E8fHxbvHx8YLx8fGC8fHxgvHx8YLx8fGC7vDshtns0K7N67zayeq288fq
s//I6rT/yOq1/8nqtv/K67f/y+u4/8vruf/P7L7w0+zF29vv0Lrn8OKX8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8/PzfvPz8xUAAAAAAAAAAPX19TLx8fGC8fHxgvHx8YLx8fGC8fHxgt3u1KXF6rHzxOmv/8Xp
sP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vruf/M67v/zey8/87svf/S7MPj4u7Zp/Hx
8YLx8fGC8fHxgvHx8YLx8fGC8/PzVQAAAAAAAAAA8fHxavHx8YLx8fGC8fHxgvHx8YLf7defwuis/cPo
rf/E6a7/xOmv/8XpsP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vruv/M67v/zey8/87s
vf/N67z/3e7SufHx8YLx8fGC8fHxgvHx8YLz8/N8////Bf///w3x8fGC8fHxgvHx8YLx8fGC8fHxgsXp
sOnB6Kv/wuis/8Porf/E6a7/xOmv/8XpsP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vr
uv/M67v/zey8/87svf/O67z96/Hoj/Hx8YLx8fGC8fHxgvHx8YLy8vIm8/PzK/Hx8YLx8fGC8fHxgvHx
8YLg79icwOep/8Hoqv/B6Kv/wuis/8Porf/E6a7/wuit/73opP+76KL/u+eh/77opv/D6a3/yeu1/8nq
tv/K67f/y+u5/8zruv/M67v/zey8/87svf/d7tSz8fHxgvHx8YLx8fGC8fHxgvHx8Tby8vI68fHxgvHx
8YLx8fGC8fHxgtTrxre/56j/wOep/8Hoqv/B6Kv/uOad/53idv+V4Gn/leBq/5fhbP+Y4W//muFx/5vi
c/+e4Xb/puWD/7PmlP/D6a3/y+u5/8zruv/M67v/zey8/9rtzsHx8fGC8fHxgvHx8YLx8fGC8/PzQfPz
80Lx8fGC8fHxgvHx8YLx8fGC0OvAwr/nqP+/56j/wOep/8Hoqv+o44b/kd9k/5LfZv+U4Gj/leBq/5fh
bf+Y4W//muFx/5vic/+d4nX/n+N3/7fnm//K67j/y+u5/8zruv/M67v/2u3QvPHx8YLx8fGC8fHxgvHx
8YLy8vI98/PzP/Hx8YLx8fGC8fHxgvHx8YLQ6sK/v+eo/7/nqP+/56j/wOep/6jjhv+P3mL/kd9k/5Lf
Zv+U4Gj/leBr/5fhbf+Y4W//muFx/5zic/+d4nX/v+mm/8nqt//K67j/y+u5/8zruv/f79au8fHxgvHx
8YLx8fGC8fHxgvX19TLx8fE38fHxgvHx8YLx8fGC8fHxgtTrybO/56j/v+eo/7/nqP+/56j/sOSS/47e
YP+P3mL/kd9k/5LfZv+U4Gj/leBr/5fhbf+Z4W//muJx/5/jd//H6bP/yeq2/8nqt//K67j/y+u5/+nv
45Tx8fGC8fHxgvHx8YLx8fGC7+/vIPHx8SXx8fGC8fHxgvHx8YLx8fGC4e/Zm7/nqP+/56j/v+eo/7/n
qP+956X/jt5h/47eYP+P3mL/kd9k/5LfZv+U4Gn/luBr/5fhbf+Z4W//q+aK/8fqs//I6rT/yeq2/8nq
t//N7Lvw8fHxgvHx8YLx8fGC8fHxgvPz84D///8G6+vrDfHx8YLx8fGC8fHxgvHx8YLv8e+Dweis87/n
qP+/56j/v+eo/7/nqP+d4XX/jN1e/47eYP+P3mL/kd9k/5PfZ/+U4Gn/luBr/5fhbf+86KP/xuqy/8fq
s//I6rX/yeq2/9Tsx8nx8fGC8fHxgvHx8YLx8fGC8PDwaAAAAAAAAAAA8fHxbPHx8YLx8fGC8fHxgvHx
8YLM6rrMv+eo/7/nqP+/56j/v+eo/7blmv+N3V//jN1e/47eYP+Q3mL/kd9k/5PfZ/+U4Gn/qeSH/8Xp
sP/G6bH/xuqy/8fqs//I6rX/5fDem/Hx8YLx8fGC8fHxgvHx8YLz8/M/AAAAAAAAAADz8/NB8fHxgvHx
8YLx8fGC8fHxgt3s06O/56j/v+eo/7/nqP+/56j/v+eo/7Xmmf+U32n/jN1e/47eYP+Q3mL/k99o/6zk
i//D6a7/xemv/8XpsP/G6bH/xuqy/8vqu+jx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8xUAAAAAAAAAAPT0
9Bfx8fGC8fHxgvHx8YLx8fGC8fHvg8Tpsee/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+35pz/suWV/7Xm
mf/A6Kj/wuit/8Porf/E6a7/xemv/8XpsP/G6bH/3e3UqvHx8YLx8fGC8fHxgvHx8YLw8PBmAAAAAAAA
AAAAAAAAAAAAAPHx8W7x8fGC8fHxgvHx8YLx8fGC4u7cmMHnqvm/56j/v+eo/7/nqP+/56j/v+eo/7/n
qP+/56j/wOep/8Hoqv/C6Kz/wuit/8Porf/E6a7/xemv/9Hrwszx8fGC8fHxgvHx8YLx8fGC8fHxgvX1
9TEAAAAAAAAAAAAAAAAAAAAA7u7uO/Hx8YLx8fGC8fHxgvHx8YLx8fGC3e7SpMHoqfq/56j/v+eo/7/n
qP+/56j/v+eo/7/nqP+/56j/wOip/8Hoq//C6Kz/wuit/8Porf/O67zV8PHwhPHx8YLx8fGC8fHxgvHx
8YLy8vJ2////BQAAAAAAAAAAAAAAAAAAAACqqqoD8PDwafHx8YLx8fGC8fHxgvHx8YLx8fGC4O/YnMTo
ruy/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/wOip/8Hoq//C6Kz90uvEwe/x74Px8fGC8fHxgvHx
8YLx8fGC8fHxgvPz8ykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADz8/MW8fHxfPHx8YLx8fGC8fHxgvHx
8YLx8fGC8PLuhdXtyLXF6bHlv+eo/7/nqP+/56j/v+eo/7/nqP/B6Kv0zeq8zOXv4JTx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLy8vJNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADy8vIm8fHxgPHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLs8OmJ4e/Zm93u06Pf7def5+/hkvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxXf///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADy8vIo8/PzffHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8VnMzMwFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD29vYb8fHxbvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz83/v7+9BgICAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwF8/PzQPLy8nnx8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz84Hx8fFc9PT0GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////B/X19TLx8fFc8PDwevHx
8YLx8fGC8fHxgvHx8YLx8fGC8fHxgPHx8Wv09PRE9PT0FwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA7+/vEPb29hvw8PAj7+/vH/T09Be/v78EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////8B///wAA//wAAD/wAAAP4AAAB+AA
AAfAAAADwAAAA4AAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAADwAAAA8AAAAPAAAAH4AAAB+AA
AA/wAAAP+AAAH/gAAD/+AAB//wAB///AA///+B////////////8oAAAAEAAAACAAAAABACAAAAAAAAAE
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CfDw8BH///8GAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAAu7u7i7x8fFe8PDwevHx8YLx8fGC8fHxgvDw
8Hvx8fFs7+/vT/Dw8CMAAAABAAAAAAAAAAAAAAAA5ubmCvLy8l/x8fGC8fHxgvHx8YLx8fGC8fHxgvHx
8YLx8fGC8fHxgvHx8YLx8fGC8/PzZu7u7g8AAAAAAAAAAPHx8V3x8fGC8fHxgunv5o7Z7c200+vFytTs
xc7W7cnH2+7QueLu2qbu8OyH8fHxgvHx8YLx8fFu////BfHx8STx8fGC8fHxgtrtzq3D6a/8xemw/8bp
sv/I6rT/yeq2/8vruP/M67v/z+u++Nzu0bjx8fGC8fHxgu/v7zDx8fFI8fHxguzw6ojC56z3wuis/8Tp
rv/E6q3/weiq/8fqsv/J6rb/y+u5/8zru//N67z/6/HpjfHx8YLy8vJN8fHxXPHx8YLg79icv+eo/8Ho
qv+k4n//lOBo/5fhbf+a4XH/n+J5/7Pmlv/L67n/zOu7/+Xw353x8fGC8fHxXvHx8Vrx8fGC4O3Zm7/n
qP+/56j/nuF3/5HfZP+U4Gj/l+Ft/5ricf+x5pL/yeq3/8vruf/r8emN8fHxgu/v70/x8fFK8fHxguzw
6ojA6Kn8v+eo/6njiP+O3mD/kd9k/5Tgaf+X4W3/vuim/8jqtP/N67zr8fHxgvHx8YLy8vI68/PzK/Hx
8YLx8fGCx+m03L/nqP++6Kb/meBw/47eYP+S32X/q+SL/8XpsP/G6rL/1+zLvvHx8YLz8/OB8PDwEdXV
1Qbx8fF98fHxgt/t1Z/A56j9v+eo/7/nqP+656H/vuim/8Lorf/E6a7/yOq18Ovw6Yvx8fGC8vLyYwAA
AAAAAAAA8fHxR/Hx8YLx8fGC2O3NrMDnqfq/56j/v+eo/7/nqP/B6Kv/xumy7OTu3Zfx8fGC8/PzgfLy
8icAAAAAAAAAAP///wPz8/Nm8fHxgvHx8YLo7+SO0+zFuczquszM6bzJ1+zMru7w7Ibx8fGC8fHxgvHx
8UcAAAAAAAAAAAAAAAAAAAAA4+PjCfHx8Vzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgfPz
80D///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8/PzK/Ly8mDz8/N+8fHxgvHx8YLy8vJ68vLyUezs
7BsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAevr6w3j4+MJAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAD8fwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIAB
AADAAwAAwAMAAOAHAADwDwAA/n8AAP//AAA=
</value>
</data>
</root>

View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,243 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using Newtonsoft.Json;
using UptimeKuma.Properties;
namespace UptimeKuma {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args) {
var cwd = Path.GetDirectoryName(Application.ExecutablePath);
if (cwd != null) {
Environment.CurrentDirectory = cwd;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new UptimeKumaApplicationContext());
}
}
public class UptimeKumaApplicationContext : ApplicationContext
{
private static Mutex mutex = null;
const string appName = "Uptime Kuma";
private NotifyIcon trayIcon;
private Process process;
private MenuItem statusMenuItem;
private MenuItem runWhenStarts;
private MenuItem openMenuItem;
private RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
public UptimeKumaApplicationContext() {
// Single instance only
bool createdNew;
mutex = new Mutex(true, appName, out createdNew);
if (!createdNew) {
return;
}
var startingText = "Starting server...";
trayIcon = new NotifyIcon();
trayIcon.Text = startingText;
runWhenStarts = new MenuItem("Run when system starts", RunWhenStarts);
runWhenStarts.Checked = registryKey.GetValue(appName) != null;
statusMenuItem = new MenuItem(startingText);
statusMenuItem.Enabled = false;
openMenuItem = new MenuItem("Open", Open);
openMenuItem.Enabled = false;
trayIcon.Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
trayIcon.ContextMenu = new ContextMenu(new MenuItem[] {
statusMenuItem,
openMenuItem,
//new("Debug Console", DebugConsole),
runWhenStarts,
new("Check for Update...", CheckForUpdate),
new("Visit GitHub...", VisitGitHub),
new("About", About),
new("Exit", Exit),
});
trayIcon.MouseDoubleClick += new MouseEventHandler(Open);
trayIcon.Visible = true;
var hasUpdateFile = File.Exists("update");
if (!hasUpdateFile && Directory.Exists("core") && Directory.Exists("node") && Directory.Exists("core/node_modules") && Directory.Exists("core/dist")) {
// Go go go
StartProcess();
} else {
DownloadFiles();
}
}
void DownloadFiles() {
var form = new DownloadForm();
form.Closed += Exit;
form.Show();
}
private void RunWhenStarts(object sender, EventArgs e) {
if (registryKey == null) {
MessageBox.Show("Error: Unable to set startup registry key.");
return;
}
if (runWhenStarts.Checked) {
registryKey.DeleteValue(appName, false);
runWhenStarts.Checked = false;
} else {
registryKey.SetValue(appName, Application.ExecutablePath);
runWhenStarts.Checked = true;
}
}
void StartProcess() {
var startInfo = new ProcessStartInfo {
FileName = "node/node.exe",
Arguments = "server/server.js --data-dir=\"../data/\"",
RedirectStandardOutput = false,
RedirectStandardError = false,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = "core"
};
process = new Process();
process.StartInfo = startInfo;
process.EnableRaisingEvents = true;
process.Exited += ProcessExited;
try {
process.Start();
//Open(null, null);
// Async task to check if the server is ready
Task.Run(() => {
var runningText = "Server is running";
using TcpClient tcpClient = new TcpClient();
while (true) {
try {
tcpClient.Connect("127.0.0.1", 3001);
statusMenuItem.Text = runningText;
openMenuItem.Enabled = true;
trayIcon.Text = runningText;
break;
} catch (Exception) {
System.Threading.Thread.Sleep(2000);
}
}
});
} catch (Exception e) {
MessageBox.Show("Startup failed: " + e.Message, "Uptime Kuma Error");
}
}
void StopProcess() {
process?.Kill();
}
void Open(object sender, EventArgs e) {
Process.Start("http://localhost:3001");
}
void DebugConsole(object sender, EventArgs e) {
}
void CheckForUpdate(object sender, EventArgs e) {
var needUpdate = false;
// Check version.json exists
if (File.Exists("version.json")) {
// Load version.json and compare with the latest version from GitHub
var currentVersionObj = JsonConvert.DeserializeObject<Version>(File.ReadAllText("version.json"));
var versionJson = new WebClient().DownloadString("https://uptime.kuma.pet/version");
var latestVersionObj = JsonConvert.DeserializeObject<Version>(versionJson);
// Compare version, if the latest version is newer, then update
if (new System.Version(latestVersionObj.latest).CompareTo(new System.Version(currentVersionObj.latest)) > 0) {
var result = MessageBox.Show("A new version is available. Do you want to update?", "Update", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes) {
// Create a empty file `update`, so the app will download the core files again at startup
File.Create("update").Close();
trayIcon.Visible = false;
process?.Kill();
// Restart the app, it will download the core files again at startup
Application.Restart();
}
} else {
MessageBox.Show("You are using the latest version.");
}
}
}
void VisitGitHub(object sender, EventArgs e)
{
Process.Start("https://github.com/louislam/uptime-kuma");
}
void About(object sender, EventArgs e)
{
MessageBox.Show("Uptime Kuma Windows Runtime v1.0.0" + Environment.NewLine + "© 2023 Louis Lam", "Info");
}
void Exit(object sender, EventArgs e)
{
// Hide tray icon, otherwise it will remain shown until user mouses over it
trayIcon.Visible = false;
process?.Kill();
Application.Exit();
}
void ProcessExited(object sender, EventArgs e) {
if (process.ExitCode != 0) {
var line = "";
while (!process.StandardOutput.EndOfStream)
{
line += process.StandardOutput.ReadLine();
}
MessageBox.Show("Uptime Kuma exited unexpectedly. Exit code: " + process.ExitCode + " " + line);
}
trayIcon.Visible = false;
Application.Exit();
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Uptime Kuma")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Uptime Kuma")]
[assembly: AssemblyCopyright("Copyright © 2023 Louis Lam")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2DB53988-1D93-4AC0-90C4-96ADEAAC5C04")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UptimeKuma.Properties {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder",
"4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance",
"CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState
.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp =
new global::System.Resources.ResourceManager("UptimeKuma.Properties.Resources",
typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState
.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get { return resourceCulture; }
set { resourceCulture = value; }
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UptimeKuma.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(
"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance =
((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get { return defaultInstance; }
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>UptimeKuma</RootNamespace>
<AssemblyName>uptime-kuma</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<ApplicationIcon>..\..\public\favicon.ico</ApplicationIcon>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>COPY "$(SolutionDir)bin\Debug\uptime-kuma.exe" "%UserProfile%\Desktop\uptime-kuma-win64\"</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll</HintPath>
</Reference>
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Console, Version=4.0.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Console.4.3.1\lib\net46\System.Console.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Diagnostics.DiagnosticSource, Version=7.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Diagnostics.DiagnosticSource.7.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll</HintPath>
</Reference>
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
</Reference>
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
</Reference>
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Linq.4.3.0\lib\net463\System.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
</Reference>
<Reference Include="System.Runtime, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Extensions, Version=4.1.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
</Reference>
<Reference Include="System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Text.RegularExpressions.4.3.1\lib\net463\System.Text.RegularExpressions.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="DownloadForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="DownloadForm.Designer.cs">
<DependentUpon>DownloadForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Version.cs" />
<EmbeddedResource Include="DownloadForm.resx">
<DependentUpon>DownloadForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="..\..\public\favicon.ico">
<Link>favicon.ico</Link>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include=".gitignore" />
<Content Include="app.manifest" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.targets'))" />
<Error Condition="!Exists('packages\Fody.6.6.4\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.6.4\build\Fody.targets'))" />
<Error Condition="!Exists('packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets'))" />
</Target>
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
<Import Project="packages\Fody.6.6.4\build\Fody.targets" Condition="Exists('packages\Fody.6.6.4\build\Fody.targets')" />
<Import Project="packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets" Condition="Exists('packages\NETStandard.Library.2.0.3\build\netstandard2.0\NETStandard.Library.targets')" />
</Project>

View File

@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UptimeKuma", "UptimeKuma.csproj", "{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=UptimeKuma_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -0,0 +1,9 @@
namespace UptimeKuma {
public class Version {
public string latest { get; set; }
public string slow { get; set; }
public string beta { get; set; }
public string nodejs { get; set; }
public string exe { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel element will disable file and registry virtualization.
Remove this element if your application requires this virtualization for backwards
compatibility.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="5.7.0" targetFramework="net472" developmentDependency="true" />
<package id="Fody" version="6.6.4" targetFramework="net472" developmentDependency="true" />
<package id="Microsoft.NETCore.Platforms" version="7.0.0" targetFramework="net472" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net472" />
<package id="NETStandard.Library" version="2.0.3" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net472" />
<package id="System.AppContext" version="4.3.0" targetFramework="net472" />
<package id="System.Console" version="4.3.1" targetFramework="net472" />
<package id="System.Diagnostics.DiagnosticSource" version="7.0.1" targetFramework="net472" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net472" />
<package id="System.Runtime.Extensions" version="4.3.1" targetFramework="net472" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.1" targetFramework="net472" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.2" targetFramework="net472" />
<package id="System.Text.RegularExpressions" version="4.3.1" targetFramework="net472" />
<package id="System.Xml.ReaderWriter" version="4.3.1" targetFramework="net472" />
<package id="System.Memory" version="4.5.5" targetFramework="net472" />
<package id="System.Net.Primitives" version="4.3.1" targetFramework="net472" />
<package id="System.Runtime" version="4.3.1" targetFramework="net472" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.Collections" version="4.3.0" targetFramework="net472" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net472" />
<package id="System.Globalization" version="4.3.0" targetFramework="net472" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net472" />
<package id="System.IO" version="4.3.0" targetFramework="net472" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net472" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net472" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net472" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Linq" version="4.3.0" targetFramework="net472" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net472" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net472" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net472" />
<package id="System.Threading" version="4.3.0" targetFramework="net472" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net472" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net472" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net472" />
</packages>

View File

@@ -11,12 +11,17 @@ import (
"net/http"
"os"
"runtime"
"strings"
"time"
)
func main() {
isFreeBSD := runtime.GOOS == "freebsd"
// Is K8S + uptime-kuma as the container name
// See #2083
isK8s := strings.HasPrefix(os.Getenv("UPTIME_KUMA_PORT"), "tcp://")
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
@@ -44,7 +49,11 @@ func main() {
hostname = "127.0.0.1"
}
port := os.Getenv("UPTIME_KUMA_PORT")
port := ""
// UPTIME_KUMA_PORT is override by K8S unexpectedly,
if !isK8s {
port = os.Getenv("UPTIME_KUMA_PORT")
}
if len(port) == 0 {
port = os.Getenv("PORT")
}

View File

@@ -1,4 +1,8 @@
/*
* ⚠️ ⚠️ ⚠️ ⚠️ Due to the weird issue in Portainer that the healthcheck script is still pointing to this script for unknown reason.
* IT CANNOT BE DROPPED, even though it looks like it is not used.
* See more: https://github.com/louislam/uptime-kuma/issues/2774#issuecomment-1429092359
*
* ⚠️ Deprecated: Changed to healthcheck.go, it will be deleted in the future.
* This script should be run after a period of time (180s), because the server may need some time to prepare.
*/

View File

@@ -1,11 +1,12 @@
const pkg = require("../package.json");
const fs = require("fs");
const util = require("../src/util");
const dayjs = require("dayjs");
util.polyfill();
const oldVersion = pkg.version;
const newVersion = oldVersion + "-nightly-" + util.genSecret(8);
const newVersion = oldVersion + "-nightly-" + dayjs().format("YYYYMMDDHHmmss");
console.log("Old Version: " + oldVersion);
console.log("New Version: " + newVersion);

View File

@@ -0,0 +1,22 @@
const fs = require("fs");
// Read the file from private/sort-contributors.txt
const file = fs.readFileSync("private/sort-contributors.txt", "utf8");
// Convert to an array of lines
let lines = file.split("\n");
// Remove empty lines
lines = lines.filter((line) => line !== "");
// Remove duplicates
lines = [ ...new Set(lines) ];
// Remove @weblate and @UptimeKumaBot
lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam");
// Sort the lines
lines = lines.sort();
// Output the lines, concat with " "
console.log(lines.join(" "));

View File

@@ -26,7 +26,8 @@ if (! exists) {
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n");
// Also update package-lock.json
childProcess.spawnSync("npm", [ "install" ]);
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
childProcess.spawnSync(npm, [ "install" ]);
commit(newVersion);
tag(newVersion);

View File

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="manifest" href="/manifest.json" />

18975
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "uptime-kuma",
"version": "1.19.6",
"version": "1.22.0-beta.0",
"license": "MIT",
"repository": {
"type": "git",
@@ -39,7 +39,7 @@
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.19.6 && npm ci --production && npm run download-dist",
"setup": "git checkout 1.21.3 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js",
"mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js",
@@ -63,18 +63,19 @@
"cy:run": "npx cypress run --browser chrome --headless --config-file ./config/cypress.config.js",
"cy:run:unit": "npx cypress run --browser chrome --headless --config-file ./config/cypress.frontend.config.js",
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"",
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go"
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go",
"deploy-demo-server": "node extra/deploy-demo-server.js",
"sort-contributors": "node extra/sort-contributors.js"
},
"dependencies": {
"@grpc/grpc-js": "~1.7.3",
"@louislam/ping": "~0.4.2-mod.1",
"@louislam/sqlite3": "15.1.2",
"@louislam/ping": "~0.4.4-mod.0",
"@louislam/sqlite3": "15.1.6",
"args-parser": "~1.3.0",
"axios": "~0.27.0",
"axios-ntlm": "1.3.0",
"badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3",
"bree": "~7.1.5",
"cacheable-lookup": "~6.0.4",
"chardet": "~1.4.0",
"check-password-strength": "^2.0.5",
@@ -83,11 +84,14 @@
"command-exists": "~1.2.9",
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"croner": "^6.0.3",
"dayjs": "~1.11.5",
"dotenv": "~16.0.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
"form-data": "~4.0.0",
"gamedig": "^4.0.5",
"http-graceful-shutdown": "~3.1.7",
"http-proxy-agent": "~5.0.0",
"https-proxy-agent": "~5.0.1",
@@ -96,9 +100,11 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
"mongodb": "~4.14.0",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",
"nanoid": "^3.3.4",
"node-cloudflared-tunnel": "~1.0.9",
"node-radius-client": "~1.0.0",
"nodemailer": "~6.6.5",
@@ -109,9 +115,11 @@
"prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1",
"protobufjs": "~7.1.1",
"qs": "~6.10.4",
"redbean-node": "~0.2.0",
"socket.io": "~4.5.3",
"socket.io-client": "~4.5.3",
"redis": "~4.5.1",
"socket.io": "~4.6.1",
"socket.io-client": "~4.6.1",
"socks-proxy-agent": "6.1.1",
"tar": "~6.1.11",
"tcp-ping": "~0.1.1",
@@ -134,18 +142,22 @@
"aedes": "^0.46.3",
"babel-plugin-rewire": "~1.2.0",
"bootstrap": "5.1.3",
"chart.js": "~3.6.2",
"chartjs-adapter-dayjs": "~1.0.0",
"chart.js": "~4.2.1",
"chartjs-adapter-dayjs-4": "~1.0.4",
"concurrently": "^7.1.0",
"core-js": "~3.26.1",
"cronstrue": "~2.24.0",
"cross-env": "~7.0.3",
"cypress": "^10.1.0",
"delay": "^5.0.0",
"dns2": "~2.0.1",
"dompurify": "~2.4.3",
"eslint": "~8.14.0",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "~0.3.10",
"jest": "~27.2.5",
"marked": "~4.2.5",
"node-ssh": "~13.0.1",
"postcss-html": "~1.5.0",
"postcss-rtlcss": "~3.7.2",
"postcss-scss": "~4.0.4",
@@ -159,10 +171,10 @@
"timezones-list": "~3.0.1",
"typescript": "~4.4.4",
"v-pagination-3": "~0.1.7",
"vite": "~3.1.0",
"vite": "~3.2.7",
"vite-plugin-compression": "^0.5.1",
"vue": "next",
"vue-chart-3": "3.0.9",
"vue": "~3.2.47",
"vue-chartjs": "~5.2.0",
"vue-confirm-dialog": "~1.0.2",
"vue-contenteditable": "~3.0.4",
"vue-i18n": "~9.2.2",
@@ -173,6 +185,7 @@
"vue-router": "~4.0.14",
"vue-toastification": "~2.0.0-rc.5",
"vuedraggable": "~4.1.0",
"wait-on": "^6.0.1"
"wait-on": "^6.0.1",
"whatwg-url": "~12.0.1"
}
}

View File

@@ -2,7 +2,9 @@ const basicAuth = require("express-basic-auth");
const passwordHash = require("./password-hash");
const { R } = require("redbean-node");
const { setting } = require("./util-server");
const { loginRateLimiter } = require("./rate-limiter");
const { loginRateLimiter, apiRateLimiter } = require("./rate-limiter");
const { Settings } = require("./settings");
const dayjs = require("dayjs");
/**
* Login to web app
@@ -34,8 +36,36 @@ exports.login = async function (username, password) {
};
/**
* Callback for myAuthorizer
* @callback myAuthorizerCB
* Validate a provided API key
* @param {string} key API key to verify
*/
async function verifyAPIKey(key) {
if (typeof key !== "string") {
return false;
}
// uk prefix + key ID is before _
let index = key.substring(2, key.indexOf("_"));
let clear = key.substring(key.indexOf("_") + 1, key.length);
let hash = await R.findOne("api_key", " id=? ", [ index ]);
if (hash === null) {
return false;
}
let current = dayjs();
let expiry = dayjs(hash.expires);
if (expiry.diff(current) < 0 || !hash.active) {
return false;
}
return hash && passwordHash.verify(clear, hash.key);
}
/**
* Callback for basic auth authorizers
* @callback authCallback
* @param {any} err Any error encountered
* @param {boolean} authorized Is the client authorized?
*/
@@ -44,9 +74,31 @@ exports.login = async function (username, password) {
* Custom authorizer for express-basic-auth
* @param {string} username
* @param {string} password
* @param {myAuthorizerCB} callback
* @param {authCallback} callback
*/
function myAuthorizer(username, password, callback) {
function apiAuthorizer(username, password, callback) {
// API Rate Limit
apiRateLimiter.pass(null, 0).then((pass) => {
if (pass) {
verifyAPIKey(password).then((valid) => {
callback(null, valid);
// Only allow a set number of api requests per minute
// (currently set to 60)
apiRateLimiter.removeTokens(1);
});
} else {
callback(null, false);
}
});
}
/**
* Custom authorizer for express-basic-auth
* @param {string} username
* @param {string} password
* @param {authCallback} callback
*/
function userAuthorizer(username, password, callback) {
// Login Rate Limit
loginRateLimiter.pass(null, 0).then((pass) => {
if (pass) {
@@ -71,7 +123,7 @@ function myAuthorizer(username, password, callback) {
*/
exports.basicAuth = async function (req, res, next) {
const middleware = basicAuth({
authorizer: myAuthorizer,
authorizer: userAuthorizer,
authorizeAsync: true,
challenge: true,
});
@@ -84,3 +136,32 @@ exports.basicAuth = async function (req, res, next) {
next();
}
};
/**
* Use use API Key if API keys enabled, else use basic auth
* @param {express.Request} req Express request object
* @param {express.Response} res Express response object
* @param {express.NextFunction} next
*/
exports.apiAuth = async function (req, res, next) {
if (!await Settings.get("disableAuth")) {
let usingAPIKeys = await Settings.get("apiKeysEnabled");
let middleware;
if (usingAPIKeys) {
middleware = basicAuth({
authorizer: apiAuthorizer,
authorizeAsync: true,
challenge: true,
});
} else {
middleware = basicAuth({
authorizer: userAuthorizer,
authorizeAsync: true,
challenge: true,
});
}
middleware(req, res, next);
} else {
next();
}
};

View File

@@ -113,6 +113,31 @@ async function sendProxyList(socket) {
return list;
}
/**
* Emit API key list to client
* @param {Socket} socket Socket.io socket instance
* @returns {Promise<void>}
*/
async function sendAPIKeyList(socket) {
const timeLogger = new TimeLogger();
let result = [];
const list = await R.find(
"api_key",
"user_id=?",
[ socket.userID ],
);
for (let bean of list) {
result.push(bean.toPublicJSON());
}
io.to(socket.userID).emit("apiKeyList", result);
timeLogger.print("Sent API Key List");
return list;
}
/**
* Emits the version information to the client.
* @param {Socket} socket Socket.io socket instance
@@ -157,6 +182,7 @@ module.exports = {
sendImportantHeartbeatList,
sendHeartbeatList,
sendProxyList,
sendAPIKeyList,
sendInfo,
sendDockerHostList
};

View File

@@ -4,13 +4,21 @@ const demoMode = args["demo"] || false;
const badgeConstants = {
naColor: "#999",
defaultUpColor: "#66c20a",
defaultWarnColor: "#eed202",
defaultDownColor: "#c2290a",
defaultPendingColor: "#f8a306",
defaultMaintenanceColor: "#1747f5",
defaultPingColor: "blue", // as defined by badge-maker / shields.io
defaultStyle: "flat",
defaultPingValueSuffix: "ms",
defaultPingLabelSuffix: "h",
defaultUptimeValueSuffix: "%",
defaultUptimeLabelSuffix: "h",
defaultCertExpValueSuffix: " days",
defaultCertExpLabelSuffix: "h",
// Values Come From Default Notification Times
defaultCertExpireWarnDays: "14",
defaultCertExpireDownDays: "7"
};
module.exports = {

View File

@@ -2,8 +2,8 @@ const fs = require("fs");
const { R } = require("redbean-node");
const { setSetting, setting } = require("./util-server");
const { log, sleep } = require("../src/util");
const dayjs = require("dayjs");
const knex = require("knex");
const { PluginsManager } = require("./plugins-manager");
/**
* Database & App Data Folder
@@ -29,11 +29,6 @@ class Database {
*/
static patched = false;
/**
* For Backup only
*/
static backupPath = null;
/**
* Add patch filename in key
* Values:
@@ -65,7 +60,16 @@ class Database {
"patch-grpc-monitor.sql": true,
"patch-add-radius-monitor.sql": true,
"patch-monitor-add-resend-interval.sql": true,
"patch-ping-packet-size.sql": true,
"patch-maintenance-table2.sql": true,
"patch-add-gamedig-monitor.sql": true,
"patch-add-google-analytics-status-page-tag.sql": true,
"patch-http-body-encoding.sql": true,
"patch-add-description-monitor.sql": true,
"patch-api-key-table.sql": true,
"patch-monitor-tls.sql": true,
"patch-maintenance-cron.sql": true,
"patch-add-parent-monitor.sql": true,
};
/**
@@ -83,6 +87,13 @@ class Database {
static init(args) {
// Data Directory (must be end with "/")
Database.dataDir = process.env.DATA_DIR || args["data-dir"] || "./data/";
// Plugin feature is working only if the dataDir = "./data";
if (Database.dataDir !== "./data/") {
log.warn("PLUGIN", "Warning: In order to enable plugin feature, you need to use the default data directory: ./data/");
PluginsManager.disable = true;
}
Database.path = Database.dataDir + "kuma.db";
if (! fs.existsSync(Database.dataDir)) {
fs.mkdirSync(Database.dataDir, { recursive: true });
@@ -183,15 +194,7 @@ class Database {
} else {
log.info("db", "Database patch is needed");
try {
this.backup(version);
} catch (e) {
log.error("db", e);
log.error("db", "Unable to create a backup before patching the database. Please make sure you have enough space and permission.");
process.exit(1);
}
// Try catch anything here, if gone wrong, restore the backup
// Try catch anything here
try {
for (let i = version + 1; i <= this.latestVersion; i++) {
const sqlFile = `./db/patch${i}.sql`;
@@ -207,7 +210,6 @@ class Database {
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);
}
}
@@ -249,8 +251,6 @@ class Database {
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();
process.exit(1);
}
@@ -352,8 +352,6 @@ class Database {
}
}
this.backup(dayjs().format("YYYYMMDDHHmmss"));
log.info("db", sqlFilename + " is patching");
this.patched = true;
await this.importSQLFile("./db/" + sqlFilename);
@@ -419,6 +417,9 @@ class Database {
log.info("db", "Closing the database");
// Flush WAL to main database
await R.exec("PRAGMA wal_checkpoint(TRUNCATE)");
while (true) {
Database.noReject = true;
await R.close();
@@ -435,90 +436,6 @@ class Database {
process.removeListener("unhandledRejection", listener);
}
/**
* One backup one time in this process.
* Reset this.backupPath if you want to backup again
* @param {string} version Version code of backup
*/
static backup(version) {
if (! this.backupPath) {
log.info("db", "Backing up the database");
this.backupPath = this.dataDir + "kuma.db.bak" + version;
fs.copyFileSync(Database.path, this.backupPath);
const shmPath = Database.path + "-shm";
if (fs.existsSync(shmPath)) {
this.backupShmPath = shmPath + ".bak" + version;
fs.copyFileSync(shmPath, this.backupShmPath);
}
const walPath = Database.path + "-wal";
if (fs.existsSync(walPath)) {
this.backupWalPath = walPath + ".bak" + version;
fs.copyFileSync(walPath, this.backupWalPath);
}
// Double confirm if all files actually backup
if (!fs.existsSync(this.backupPath)) {
throw new Error("Backup failed! " + this.backupPath);
}
if (fs.existsSync(shmPath)) {
if (!fs.existsSync(this.backupShmPath)) {
throw new Error("Backup failed! " + this.backupShmPath);
}
}
if (fs.existsSync(walPath)) {
if (!fs.existsSync(this.backupWalPath)) {
throw new Error("Backup failed! " + this.backupWalPath);
}
}
}
}
/** Restore from most recent backup */
static restore() {
if (this.backupPath) {
log.error("db", "Patching the database failed!!! Restoring the backup");
const shmPath = Database.path + "-shm";
const walPath = Database.path + "-wal";
// Delete patch failed db
try {
if (fs.existsSync(Database.path)) {
fs.unlinkSync(Database.path);
}
if (fs.existsSync(shmPath)) {
fs.unlinkSync(shmPath);
}
if (fs.existsSync(walPath)) {
fs.unlinkSync(walPath);
}
} catch (e) {
log.error("db", "Restore failed; you may need to restore the backup manually");
process.exit(1);
}
// Restore backup
fs.copyFileSync(this.backupPath, Database.path);
if (this.backupShmPath) {
fs.copyFileSync(this.backupShmPath, shmPath);
}
if (this.backupWalPath) {
fs.copyFileSync(this.backupWalPath, walPath);
}
} else {
log.info("db", "Nothing to restore");
}
}
/** Get the size of the database */
static getSize() {
log.debug("db", "Database.getSize()");

24
server/git.js Normal file
View File

@@ -0,0 +1,24 @@
const childProcess = require("child_process");
class Git {
static clone(repoURL, cwd, targetDir = ".") {
let result = childProcess.spawnSync("git", [
"clone",
repoURL,
targetDir,
], {
cwd: cwd,
});
if (result.status !== 0) {
throw new Error(result.stderr.toString("utf-8"));
} else {
return result.stdout.toString("utf-8") + result.stderr.toString("utf-8");
}
}
}
module.exports = {
Git,
};

View File

@@ -0,0 +1,24 @@
const jsesc = require("jsesc");
/**
* Returns a string that represents the javascript that is required to insert the Google Analytics scripts
* into a webpage.
* @param tagId Google UA/G/AW/DC Property ID to use with the Google Analytics script.
* @returns {string}
*/
function getGoogleAnalyticsScript(tagId) {
let escapedTagId = jsesc(tagId, { isScriptContext: true });
if (escapedTagId) {
escapedTagId = escapedTagId.trim();
}
return `
<script async src="https://www.googletagmanager.com/gtag/js?id=${escapedTagId}"></script>
<script>window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date());gtag('config', '${escapedTagId}'); </script>
`;
}
module.exports = {
getGoogleAnalyticsScript,
};

View File

@@ -1,41 +1,44 @@
const path = require("path");
const Bree = require("bree");
const { SHARE_ENV } = require("worker_threads");
const { log } = require("../src/util");
let bree;
const { UptimeKumaServer } = require("./uptime-kuma-server");
const { clearOldData } = require("./jobs/clear-old-data");
const Cron = require("croner");
const jobs = [
{
name: "clear-old-data",
interval: "at 03:14",
interval: "14 03 * * *",
jobFunc: clearOldData,
croner: null,
},
];
/**
* Initialize background jobs
* @param {Object} args Arguments to pass to workers
* @returns {Bree}
* @returns {Promise<void>}
*/
const initBackgroundJobs = function (args) {
bree = new Bree({
root: path.resolve("server", "jobs"),
jobs,
worker: {
env: SHARE_ENV,
workerData: args,
},
workerMessageHandler: (message) => {
log.info("jobs", message);
}
});
const initBackgroundJobs = async function () {
const timezone = await UptimeKumaServer.getInstance().getTimezone();
for (const job of jobs) {
const cornerJob = new Cron(
job.interval,
{
name: job.name,
timezone,
},
job.jobFunc,
);
job.croner = cornerJob;
}
bree.start();
return bree;
};
/** Stop all background jobs if running */
const stopBackgroundJobs = function () {
if (bree) {
bree.stop();
for (const job of jobs) {
if (job.croner) {
job.croner.stop();
job.croner = null;
}
}
};

View File

@@ -1,12 +1,15 @@
const { log, exit, connectDb } = require("./util-worker");
const { R } = require("redbean-node");
const { log } = require("../../src/util");
const { setSetting, setting } = require("../util-server");
const DEFAULT_KEEP_PERIOD = 180;
(async () => {
await connectDb();
/**
* Clears old data from the heartbeat table of the database.
* @return {Promise<void>} A promise that resolves when the data has been cleared.
*/
const clearOldData = async () => {
let period = await setting("keepDataPeriodDays");
// Set Default Period
@@ -20,16 +23,16 @@ const DEFAULT_KEEP_PERIOD = 180;
try {
parsedPeriod = parseInt(period);
} catch (_) {
log("Failed to parse setting, resetting to default..");
log.warn("clearOldData", "Failed to parse setting, resetting to default..");
await setSetting("keepDataPeriodDays", DEFAULT_KEEP_PERIOD, "general");
parsedPeriod = DEFAULT_KEEP_PERIOD;
}
if (parsedPeriod < 1) {
log(`Data deletion has been disabled as period is less than 1. Period is ${parsedPeriod} days.`);
log.info("clearOldData", `Data deletion has been disabled as period is less than 1. Period is ${parsedPeriod} days.`);
} else {
log(`Clearing Data older than ${parsedPeriod} days...`);
log.debug("clearOldData", `Clearing Data older than ${parsedPeriod} days...`);
try {
await R.exec(
@@ -37,9 +40,11 @@ const DEFAULT_KEEP_PERIOD = 180;
[ parsedPeriod ]
);
} catch (e) {
log(`Failed to clear old data: ${e.message}`);
log.error("clearOldData", `Failed to clear old data: ${e.message}`);
}
}
};
exit();
})();
module.exports = {
clearOldData,
};

View File

@@ -1,50 +0,0 @@
const { parentPort, workerData } = require("worker_threads");
const Database = require("../database");
const path = require("path");
/**
* Send message to parent process for logging
* since worker_thread does not have access to stdout, this is used
* instead of console.log()
* @param {any} any The message to log
*/
const log = function (any) {
if (parentPort) {
parentPort.postMessage(any);
}
};
/**
* Exit the worker process
* @param {number} error The status code to exit
*/
const exit = function (error) {
if (error && error !== 0) {
process.exit(error);
} else {
if (parentPort) {
parentPort.postMessage("done");
} else {
process.exit(0);
}
}
};
/** Connects to the database */
const connectDb = async function () {
const dbPath = path.join(
process.env.DATA_DIR || workerData["data-dir"] || "./data/"
);
Database.init({
"data-dir": dbPath,
});
await Database.connect();
};
module.exports = {
log,
exit,
connectDb,
};

76
server/model/api_key.js Normal file
View File

@@ -0,0 +1,76 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const { R } = require("redbean-node");
const dayjs = require("dayjs");
class APIKey extends BeanModel {
/**
* Get the current status of this API key
* @returns {string} active, inactive or expired
*/
getStatus() {
let current = dayjs();
let expiry = dayjs(this.expires);
if (expiry.diff(current) < 0) {
return "expired";
}
return this.active ? "active" : "inactive";
}
/**
* Returns an object that ready to parse to JSON
* @returns {Object}
*/
toJSON() {
return {
id: this.id,
key: this.key,
name: this.name,
userID: this.user_id,
createdDate: this.created_date,
active: this.active,
expires: this.expires,
status: this.getStatus(),
};
}
/**
* Returns an object that ready to parse to JSON with sensitive fields
* removed
* @returns {Object}
*/
toPublicJSON() {
return {
id: this.id,
name: this.name,
userID: this.user_id,
createdDate: this.created_date,
active: this.active,
expires: this.expires,
status: this.getStatus(),
};
}
/**
* Create a new API Key and store it in the database
* @param {Object} key Object sent by client
* @param {int} userID ID of socket user
* @returns {Promise<bean>}
*/
static async save(key, userID) {
let bean;
bean = R.dispense("api_key");
bean.key = key.key;
bean.name = key.name;
bean.user_id = userID;
bean.active = key.active;
bean.expires = key.expires;
await R.store(bean);
return bean;
}
}
module.exports = APIKey;

View File

@@ -1,8 +1,10 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const { parseTimeObject, parseTimeFromTimeObject, utcToLocal, localToUTC, log } = require("../../src/util");
const { timeObjectToUTC, timeObjectToLocal } = require("../util-server");
const { parseTimeObject, parseTimeFromTimeObject, log } = require("../../src/util");
const { R } = require("redbean-node");
const dayjs = require("dayjs");
const Cron = require("croner");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const apicache = require("../modules/apicache");
class Maintenance extends BeanModel {
@@ -15,16 +17,19 @@ class Maintenance extends BeanModel {
let dateRange = [];
if (this.start_date) {
dateRange.push(utcToLocal(this.start_date));
if (this.end_date) {
dateRange.push(utcToLocal(this.end_date));
}
dateRange.push(this.start_date);
} else {
dateRange.push(null);
}
if (this.end_date) {
dateRange.push(this.end_date);
}
let timeRange = [];
let startTime = timeObjectToLocal(parseTimeObject(this.start_time));
let startTime = parseTimeObject(this.start_time);
timeRange.push(startTime);
let endTime = timeObjectToLocal(parseTimeObject(this.end_time));
let endTime = parseTimeObject(this.end_time);
timeRange.push(endTime);
let obj = {
@@ -39,12 +44,44 @@ class Maintenance extends BeanModel {
weekdays: (this.weekdays) ? JSON.parse(this.weekdays) : [],
daysOfMonth: (this.days_of_month) ? JSON.parse(this.days_of_month) : [],
timeslotList: [],
cron: this.cron,
duration: this.duration,
durationMinutes: parseInt(this.duration / 60),
timezone: await this.getTimezone(), // Only valid timezone
timezoneOption: this.timezone, // Mainly for dropdown menu, because there is a option "SAME_AS_SERVER"
timezoneOffset: await this.getTimezoneOffset(),
status: await this.getStatus(),
};
const timeslotList = await this.getTimeslotList();
if (this.strategy === "manual") {
// Do nothing, no timeslots
} else if (this.strategy === "single") {
obj.timeslotList.push({
startDate: this.start_date,
endDate: this.end_date,
});
} else {
// Should be cron or recurring here
if (this.beanMeta.job) {
let runningTimeslot = this.getRunningTimeslot();
for (let timeslot of timeslotList) {
obj.timeslotList.push(await timeslot.toPublicJSON());
if (runningTimeslot) {
obj.timeslotList.push(runningTimeslot);
}
let nextRunDate = this.beanMeta.job.nextRun();
if (nextRunDate) {
let startDateDayjs = dayjs(nextRunDate);
let startDate = startDateDayjs.toISOString();
let endDate = startDateDayjs.add(this.duration, "second").toISOString();
obj.timeslotList.push({
startDate,
endDate,
});
}
}
}
if (!Array.isArray(obj.weekdays)) {
@@ -55,54 +92,9 @@ class Maintenance extends BeanModel {
obj.daysOfMonth = [];
}
// Maintenance Status
if (!obj.active) {
obj.status = "inactive";
} else if (obj.strategy === "manual") {
obj.status = "under-maintenance";
} else if (obj.timeslotList.length > 0) {
let currentTimestamp = dayjs().unix();
for (let timeslot of obj.timeslotList) {
if (dayjs.utc(timeslot.startDate).unix() <= currentTimestamp && dayjs.utc(timeslot.endDate).unix() >= currentTimestamp) {
log.debug("timeslot", "Timeslot ID: " + timeslot.id);
log.debug("timeslot", "currentTimestamp:" + currentTimestamp);
log.debug("timeslot", "timeslot.start_date:" + dayjs.utc(timeslot.startDate).unix());
log.debug("timeslot", "timeslot.end_date:" + dayjs.utc(timeslot.endDate).unix());
obj.status = "under-maintenance";
break;
}
}
if (!obj.status) {
obj.status = "scheduled";
}
} else if (obj.timeslotList.length === 0) {
obj.status = "ended";
} else {
obj.status = "unknown";
}
return obj;
}
/**
* Only get future or current timeslots only
* @returns {Promise<[]>}
*/
async getTimeslotList() {
return R.convertToBeans("maintenance_timeslot", await R.getAll(`
SELECT maintenance_timeslot.*
FROM maintenance_timeslot, maintenance
WHERE maintenance_timeslot.maintenance_id = maintenance.id
AND maintenance.id = ?
AND ${Maintenance.getActiveAndFutureMaintenanceSQLCondition()}
`, [
this.id
]));
}
/**
* Return an object that ready to parse to JSON
* @param {string} timezone If not specified, the timeRange will be in UTC
@@ -126,7 +118,7 @@ class Maintenance extends BeanModel {
/**
* Get a list of days in month that maintenance is active for
* @returns {number[]} Array of active days in month
* @returns {number[]|string[]} Array of active days in month
*/
getDayOfMonthList() {
return JSON.parse(this.days_of_month).sort(function (a, b) {
@@ -135,26 +127,10 @@ class Maintenance extends BeanModel {
}
/**
* Get the start date and time for maintenance
* @returns {dayjs.Dayjs} Start date and time
*/
getStartDateTime() {
let startOfTheDay = dayjs.utc(this.start_date).format("HH:mm");
log.debug("timeslot", "startOfTheDay: " + startOfTheDay);
// Start Time
let startTimeSecond = dayjs.utc(this.start_time, "HH:mm").diff(dayjs.utc(startOfTheDay, "HH:mm"), "second");
log.debug("timeslot", "startTime: " + startTimeSecond);
// Bake StartDate + StartTime = Start DateTime
return dayjs.utc(this.start_date).add(startTimeSecond, "second");
}
/**
* Get the duraction of maintenance in seconds
* Get the duration of maintenance in seconds
* @returns {number} Duration of maintenance
*/
getDuration() {
calcDuration() {
let duration = dayjs.utc(this.end_time, "HH:mm").diff(dayjs.utc(this.start_time, "HH:mm"), "second");
// Add 24hours if it is across day
if (duration < 0) {
@@ -169,71 +145,270 @@ class Maintenance extends BeanModel {
* @param {Object} obj Data to fill bean with
* @returns {Bean} Filled bean
*/
static jsonToBean(bean, obj) {
static async jsonToBean(bean, obj) {
if (obj.id) {
bean.id = obj.id;
}
// Apply timezone offset to timeRange, as it cannot apply automatically.
if (obj.timeRange[0]) {
timeObjectToUTC(obj.timeRange[0]);
if (obj.timeRange[1]) {
timeObjectToUTC(obj.timeRange[1]);
}
}
bean.title = obj.title;
bean.description = obj.description;
bean.strategy = obj.strategy;
bean.interval_day = obj.intervalDay;
bean.timezone = obj.timezoneOption;
bean.active = obj.active;
if (obj.dateRange[0]) {
bean.start_date = localToUTC(obj.dateRange[0]);
if (obj.dateRange[1]) {
bean.end_date = localToUTC(obj.dateRange[1]);
}
bean.start_date = obj.dateRange[0];
} else {
bean.start_date = null;
}
bean.start_time = parseTimeFromTimeObject(obj.timeRange[0]);
bean.end_time = parseTimeFromTimeObject(obj.timeRange[1]);
if (obj.dateRange[1]) {
bean.end_date = obj.dateRange[1];
} else {
bean.end_date = null;
}
bean.weekdays = JSON.stringify(obj.weekdays);
bean.days_of_month = JSON.stringify(obj.daysOfMonth);
if (bean.strategy === "cron") {
bean.duration = obj.durationMinutes * 60;
bean.cron = obj.cron;
this.validateCron(bean.cron);
}
if (bean.strategy.startsWith("recurring-")) {
bean.start_time = parseTimeFromTimeObject(obj.timeRange[0]);
bean.end_time = parseTimeFromTimeObject(obj.timeRange[1]);
bean.weekdays = JSON.stringify(obj.weekdays);
bean.days_of_month = JSON.stringify(obj.daysOfMonth);
await bean.generateCron();
this.validateCron(bean.cron);
}
return bean;
}
/**
* SQL conditions for active maintenance
* @returns {string}
* Throw error if cron is invalid
* @param cron
* @returns {Promise<void>}
*/
static getActiveMaintenanceSQLCondition() {
return `
(
(maintenance_timeslot.start_date <= DATETIME('now')
AND maintenance_timeslot.end_date >= DATETIME('now')
AND maintenance.active = 1)
OR
(maintenance.strategy = 'manual' AND active = 1)
)
`;
static async validateCron(cron) {
let job = new Cron(cron, () => {});
job.stop();
}
/**
* SQL conditions for active and future maintenance
* @returns {string}
* Run the cron
*/
static getActiveAndFutureMaintenanceSQLCondition() {
return `
(
((maintenance_timeslot.end_date >= DATETIME('now')
AND maintenance.active = 1)
OR
(maintenance.strategy = 'manual' AND active = 1))
)
`;
async run(throwError = false) {
if (this.beanMeta.job) {
log.debug("maintenance", "Maintenance is already running, stop it first. id: " + this.id);
this.stop();
}
log.debug("maintenance", "Run maintenance id: " + this.id);
// 1.21.2 migration
if (!this.cron) {
await this.generateCron();
if (!this.timezone) {
this.timezone = "UTC";
}
if (this.cron) {
await R.store(this);
}
}
if (this.strategy === "manual") {
// Do nothing, because it is controlled by the user
} else if (this.strategy === "single") {
this.beanMeta.job = new Cron(this.start_date, { timezone: await this.getTimezone() }, () => {
log.info("maintenance", "Maintenance id: " + this.id + " is under maintenance now");
UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id);
apicache.clear();
});
} else if (this.cron != null) {
// Here should be cron or recurring
try {
this.beanMeta.status = "scheduled";
let startEvent = (customDuration = 0) => {
log.info("maintenance", "Maintenance id: " + this.id + " is under maintenance now");
this.beanMeta.status = "under-maintenance";
clearTimeout(this.beanMeta.durationTimeout);
// Check if duration is still in the window. If not, use the duration from the current time to the end of the window
let duration;
if (customDuration > 0) {
duration = customDuration;
} else if (this.end_date) {
let d = dayjs(this.end_date).diff(dayjs(), "second");
if (d < this.duration) {
duration = d * 1000;
}
} else {
duration = this.duration * 1000;
}
UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id);
this.beanMeta.durationTimeout = setTimeout(() => {
// End of maintenance for this timeslot
this.beanMeta.status = "scheduled";
UptimeKumaServer.getInstance().sendMaintenanceListByUserID(this.user_id);
}, duration);
};
// Create Cron
this.beanMeta.job = new Cron(this.cron, {
timezone: await this.getTimezone(),
}, startEvent);
// Continue if the maintenance is still in the window
let runningTimeslot = this.getRunningTimeslot();
let current = dayjs();
if (runningTimeslot) {
let duration = dayjs(runningTimeslot.endDate).diff(current, "second") * 1000;
log.debug("maintenance", "Maintenance id: " + this.id + " Remaining duration: " + duration + "ms");
startEvent(duration);
}
} catch (e) {
log.error("maintenance", "Error in maintenance id: " + this.id);
log.error("maintenance", "Cron: " + this.cron);
log.error("maintenance", e);
if (throwError) {
throw e;
}
}
} else {
log.error("maintenance", "Maintenance id: " + this.id + " has no cron");
}
}
getRunningTimeslot() {
let start = dayjs(this.beanMeta.job.nextRun(dayjs().add(-this.duration, "second").toDate()));
let end = start.add(this.duration, "second");
let current = dayjs();
if (current.isAfter(start) && current.isBefore(end)) {
return {
startDate: start.toISOString(),
endDate: end.toISOString(),
};
} else {
return null;
}
}
stop() {
if (this.beanMeta.job) {
this.beanMeta.job.stop();
delete this.beanMeta.job;
}
}
async isUnderMaintenance() {
return (await this.getStatus()) === "under-maintenance";
}
async getTimezone() {
if (!this.timezone || this.timezone === "SAME_AS_SERVER") {
return await UptimeKumaServer.getInstance().getTimezone();
}
return this.timezone;
}
async getTimezoneOffset() {
return dayjs.tz(dayjs(), await this.getTimezone()).format("Z");
}
async getStatus() {
if (!this.active) {
return "inactive";
}
if (this.strategy === "manual") {
return "under-maintenance";
}
// Check if the maintenance is started
if (this.start_date && dayjs().isBefore(dayjs.tz(this.start_date, await this.getTimezone()))) {
return "scheduled";
}
// Check if the maintenance is ended
if (this.end_date && dayjs().isAfter(dayjs.tz(this.end_date, await this.getTimezone()))) {
return "ended";
}
if (this.strategy === "single") {
return "under-maintenance";
}
if (!this.beanMeta.status) {
return "unknown";
}
return this.beanMeta.status;
}
/**
* Generate Cron for recurring maintenance
* @returns {Promise<void>}
*/
async generateCron() {
log.info("maintenance", "Generate cron for maintenance id: " + this.id);
if (this.strategy === "cron") {
// Do nothing for cron
} else if (!this.strategy.startsWith("recurring-")) {
this.cron = "";
} else if (this.strategy === "recurring-interval") {
let array = this.start_time.split(":");
let hour = parseInt(array[0]);
let minute = parseInt(array[1]);
this.cron = minute + " " + hour + " */" + this.interval_day + " * *";
this.duration = this.calcDuration();
log.debug("maintenance", "Cron: " + this.cron);
log.debug("maintenance", "Duration: " + this.duration);
} else if (this.strategy === "recurring-weekday") {
let list = this.getDayOfWeekList();
let array = this.start_time.split(":");
let hour = parseInt(array[0]);
let minute = parseInt(array[1]);
this.cron = minute + " " + hour + " * * " + list.join(",");
this.duration = this.calcDuration();
} else if (this.strategy === "recurring-day-of-month") {
let list = this.getDayOfMonthList();
let array = this.start_time.split(":");
let hour = parseInt(array[0]);
let minute = parseInt(array[1]);
let dayList = [];
for (let day of list) {
if (typeof day === "string" && day.startsWith("lastDay")) {
if (day === "lastDay1") {
dayList.push("L");
}
// Unfortunately, lastDay2-4 is not supported by cron
} else {
dayList.push(day);
}
}
// Remove duplicate
dayList = [ ...new Set(dayList) ];
this.cron = minute + " " + hour + " " + dayList.join(",") + " * *";
this.duration = this.calcDuration();
}
}
}

View File

@@ -1,198 +0,0 @@
const { BeanModel } = require("redbean-node/dist/bean-model");
const { R } = require("redbean-node");
const dayjs = require("dayjs");
const { log, utcToLocal, SQL_DATETIME_FORMAT_WITHOUT_SECOND, localToUTC } = require("../../src/util");
const { UptimeKumaServer } = require("../uptime-kuma-server");
class MaintenanceTimeslot extends BeanModel {
/**
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @returns {Object}
*/
async toPublicJSON() {
const serverTimezoneOffset = UptimeKumaServer.getInstance().getTimezoneOffset();
const obj = {
id: this.id,
startDate: this.start_date,
endDate: this.end_date,
startDateServerTimezone: utcToLocal(this.start_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
endDateServerTimezone: utcToLocal(this.end_date, SQL_DATETIME_FORMAT_WITHOUT_SECOND),
serverTimezoneOffset,
};
return obj;
}
/**
* Return an object that ready to parse to JSON
* @returns {Object}
*/
async toJSON() {
return await this.toPublicJSON();
}
/**
* @param {Maintenance} maintenance
* @param {dayjs} minDate (For recurring type only) Generate a next timeslot from this date.
* @param {boolean} removeExist Remove existing timeslot before create
* @returns {Promise<MaintenanceTimeslot>}
*/
static async generateTimeslot(maintenance, minDate = null, removeExist = false) {
if (removeExist) {
await R.exec("DELETE FROM maintenance_timeslot WHERE maintenance_id = ? ", [
maintenance.id
]);
}
if (maintenance.strategy === "manual") {
log.debug("maintenance", "No need to generate timeslot for manual type");
} else if (maintenance.strategy === "single") {
let bean = R.dispense("maintenance_timeslot");
bean.maintenance_id = maintenance.id;
bean.start_date = maintenance.start_date;
bean.end_date = maintenance.end_date;
bean.generated_next = true;
return await R.store(bean);
} else if (maintenance.strategy === "recurring-interval") {
// Prevent dead loop, in case interval_day is not set
if (!maintenance.interval_day || maintenance.interval_day <= 0) {
maintenance.interval_day = 1;
}
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
return startDateTime.add(maintenance.interval_day, "day");
}, () => {
return true;
});
} else if (maintenance.strategy === "recurring-weekday") {
let dayOfWeekList = maintenance.getDayOfWeekList();
log.debug("timeslot", dayOfWeekList);
if (dayOfWeekList.length <= 0) {
log.debug("timeslot", "No weekdays selected?");
return null;
}
const isValid = (startDateTime) => {
log.debug("timeslot", "nextDateTime: " + startDateTime);
let day = startDateTime.local().day();
log.debug("timeslot", "nextDateTime.day(): " + day);
return dayOfWeekList.includes(day);
};
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
while (true) {
startDateTime = startDateTime.add(1, "day");
if (isValid(startDateTime)) {
return startDateTime;
}
}
}, isValid);
} else if (maintenance.strategy === "recurring-day-of-month") {
let dayOfMonthList = maintenance.getDayOfMonthList();
if (dayOfMonthList.length <= 0) {
log.debug("timeslot", "No day selected?");
return null;
}
const isValid = (startDateTime) => {
let day = parseInt(startDateTime.local().format("D"));
log.debug("timeslot", "day: " + day);
// Check 1-31
if (dayOfMonthList.includes(day)) {
return startDateTime;
}
// Check "lastDay1","lastDay2"...
let daysInMonth = startDateTime.daysInMonth();
let lastDayList = [];
// Small first, e.g. 28 > 29 > 30 > 31
for (let i = 4; i >= 1; i--) {
if (dayOfMonthList.includes("lastDay" + i)) {
lastDayList.push(daysInMonth - i + 1);
}
}
log.debug("timeslot", lastDayList);
return lastDayList.includes(day);
};
return await this.handleRecurringType(maintenance, minDate, (startDateTime) => {
while (true) {
startDateTime = startDateTime.add(1, "day");
if (isValid(startDateTime)) {
return startDateTime;
}
}
}, isValid);
} else {
throw new Error("Unknown maintenance strategy");
}
}
/**
* Generate a next timeslot for all recurring types
* @param maintenance
* @param minDate
* @param {function} nextDayCallback The logic how to get the next possible day
* @param {function} isValidCallback Check the day whether is matched the current strategy
* @returns {Promise<null|MaintenanceTimeslot>}
*/
static async handleRecurringType(maintenance, minDate, nextDayCallback, isValidCallback) {
let bean = R.dispense("maintenance_timeslot");
let duration = maintenance.getDuration();
let startDateTime = maintenance.getStartDateTime();
let endDateTime;
// Keep generating from the first possible date, until it is ok
while (true) {
log.debug("timeslot", "startDateTime: " + startDateTime.format());
// Handling out of effective date range
if (startDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
log.debug("timeslot", "Out of effective date range");
return null;
}
endDateTime = startDateTime.add(duration, "second");
// If endDateTime is out of effective date range, use the end datetime from effective date range
if (endDateTime.diff(dayjs.utc(maintenance.end_date)) > 0) {
endDateTime = dayjs.utc(maintenance.end_date);
}
// If minDate is set, the endDateTime must be bigger than it.
// And the endDateTime must be bigger current time
// Is valid under current recurring strategy
if (
(!minDate || endDateTime.diff(minDate) > 0) &&
endDateTime.diff(dayjs()) > 0 &&
isValidCallback(startDateTime)
) {
break;
}
startDateTime = nextDayCallback(startDateTime);
}
bean.maintenance_id = maintenance.id;
bean.start_date = localToUTC(startDateTime);
bean.end_date = localToUTC(endDateTime);
bean.generated_next = false;
return await R.store(bean);
}
}
module.exports = MaintenanceTimeslot;

View File

@@ -2,8 +2,12 @@ const https = require("https");
const dayjs = require("dayjs");
const axios = require("axios");
const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND,
SQL_DATETIME_FORMAT
} = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery,
redisPingAsync, mongodbPing,
} = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
const { Notification } = require("../notification");
@@ -14,8 +18,8 @@ const apicache = require("../modules/apicache");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent");
const { DockerHost } = require("../docker");
const Maintenance = require("./maintenance");
const { UptimeCacheList } = require("../uptime-cache-list");
const Gamedig = require("gamedig");
/**
* status:
@@ -69,13 +73,18 @@ class Monitor extends BeanModel {
let data = {
id: this.id,
name: this.name,
description: this.description,
pathName: await this.getPathName(),
parent: this.parent,
childrenIDs: await Monitor.getAllChildrenIDs(this.id),
url: this.url,
method: this.method,
hostname: this.hostname,
port: this.port,
maxretries: this.maxretries,
weight: this.weight,
active: this.active,
active: await this.isActive(),
forceInactive: !await Monitor.isParentActive(this.id),
type: this.type,
interval: this.interval,
retryInterval: this.retryInterval,
@@ -84,6 +93,7 @@ class Monitor extends BeanModel {
expiryNotification: this.isEnabledExpiryNotification(),
ignoreTls: this.getIgnoreTls(),
upsideDown: this.isUpsideDown(),
packetSize: this.packetSize,
maxredirects: this.maxredirects,
accepted_statuscodes: this.getAcceptedStatuscodes(),
dns_resolve_type: this.dns_resolve_type,
@@ -106,6 +116,8 @@ class Monitor extends BeanModel {
grpcEnableTls: this.getGrpcEnableTls(),
radiusCalledStationId: this.radiusCalledStationId,
radiusCallingStationId: this.radiusCallingStationId,
game: this.game,
httpBodyEncoding: this.httpBodyEncoding
};
if (includeSensitiveData) {
@@ -126,6 +138,9 @@ class Monitor extends BeanModel {
mqttPassword: this.mqttPassword,
authWorkstation: this.authWorkstation,
authDomain: this.authDomain,
tlsCa: this.tlsCa,
tlsCert: this.tlsCert,
tlsKey: this.tlsKey,
};
}
@@ -133,12 +148,22 @@ class Monitor extends BeanModel {
return data;
}
/**
* Checks if the monitor is active based on itself and its parents
* @returns {Promise<Boolean>}
*/
async isActive() {
const parentActive = await Monitor.isParentActive(this.id);
return this.active && parentActive;
}
/**
* Get all tags applied to this monitor
* @returns {Promise<LooseObject<any>[]>}
*/
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 ]);
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 = ? ORDER BY tag.name", [ this.id ]);
}
/**
@@ -198,7 +223,7 @@ class Monitor extends BeanModel {
let previousBeat = null;
let retries = 0;
let prometheus = new Prometheus(this);
this.prometheus = new Prometheus(this);
const beat = async () => {
@@ -248,6 +273,36 @@ class Monitor extends BeanModel {
if (await Monitor.isUnderMaintenance(this.id)) {
bean.msg = "Monitor under maintenance";
bean.status = MAINTENANCE;
} else if (this.type === "group") {
const children = await Monitor.getChildren(this.id);
if (children.length > 0) {
bean.status = UP;
bean.msg = "All children up and running";
for (const child of children) {
if (!child.active) {
// Ignore inactive childs
continue;
}
const lastBeat = await Monitor.getPreviousHeartbeat(child.id);
// Only change state if the monitor is in worse conditions then the ones before
if (bean.status === UP && (lastBeat.status === PENDING || lastBeat.status === DOWN)) {
bean.status = lastBeat.status;
} else if (bean.status === PENDING && lastBeat.status === DOWN) {
bean.status = lastBeat.status;
}
}
if (bean.status !== UP) {
bean.msg = "Child inaccessible";
}
} else {
// Set status pending if group is empty
bean.status = PENDING;
bean.msg = "Group empty";
}
} else if (this.type === "http" || this.type === "keyword") {
// Do not do any queries/high loading things before the "bean.ping"
let startTime = dayjs().valueOf();
@@ -267,17 +322,34 @@ class Monitor extends BeanModel {
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
let contentType = null;
let bodyValue = null;
if (this.body && (typeof this.body === "string" && this.body.trim().length > 0)) {
if (!this.httpBodyEncoding || this.httpBodyEncoding === "json") {
try {
bodyValue = JSON.parse(this.body);
contentType = "application/json";
} catch (e) {
throw new Error("Your JSON body is invalid. " + e.message);
}
} else if (this.httpBodyEncoding === "xml") {
bodyValue = this.body;
contentType = "text/xml; charset=utf-8";
}
}
// Axios Options
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": "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) : {}),
...(contentType ? { "Content-Type": contentType } : {}),
...(basicAuthHeader),
...(this.headers ? JSON.parse(this.headers) : {})
},
maxRedirects: this.maxredirects,
validateStatus: (status) => {
@@ -285,6 +357,10 @@ class Monitor extends BeanModel {
},
};
if (bodyValue) {
options.data = bodyValue;
}
if (this.proxy_id) {
const proxy = await R.load("proxy", this.proxy_id);
@@ -303,6 +379,18 @@ class Monitor extends BeanModel {
options.httpsAgent = new https.Agent(httpsAgentOptions);
}
if (this.auth_method === "mtls") {
if (this.tlsCert !== null && this.tlsCert !== "") {
options.httpsAgent.options.cert = Buffer.from(this.tlsCert);
}
if (this.tlsCa !== null && this.tlsCa !== "") {
options.httpsAgent.options.ca = Buffer.from(this.tlsCa);
}
if (this.tlsKey !== null && this.tlsKey !== "") {
options.httpsAgent.options.key = Buffer.from(this.tlsKey);
}
}
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
log.debug("monitor", `[${this.name}] Axios Request`);
@@ -321,8 +409,8 @@ class Monitor extends BeanModel {
tlsInfo = await this.updateTlsInfo(tlsInfoObject);
if (!this.getIgnoreTls() && this.isEnabledExpiryNotification()) {
log.debug("monitor", `[${this.name}] call sendCertNotification`);
await this.sendCertNotification(tlsInfoObject);
log.debug("monitor", `[${this.name}] call checkCertExpiryNotifications`);
await this.checkCertExpiryNotifications(tlsInfoObject);
}
} catch (e) {
@@ -356,7 +444,7 @@ class Monitor extends BeanModel {
bean.msg += ", keyword is found";
bean.status = UP;
} else {
data = data.replace(/<[^>]*>?|[\n\r]|\s+/gm, " ");
data = data.replace(/<[^>]*>?|[\n\r]|\s+/gm, " ").trim();
if (data.length > 50) {
data = data.substring(0, 47) + "...";
}
@@ -371,7 +459,7 @@ class Monitor extends BeanModel {
bean.status = UP;
} else if (this.type === "ping") {
bean.ping = await ping(this.hostname);
bean.ping = await ping(this.hostname, this.packetSize);
bean.msg = "";
bean.status = UP;
} else if (this.type === "dns") {
@@ -481,25 +569,44 @@ class Monitor extends BeanModel {
bean.msg = res.data.response.servers[0].name;
try {
bean.ping = await ping(this.hostname);
bean.ping = await ping(this.hostname, this.packetSize);
} catch (_) { }
} else {
throw new Error("Server not found on Steam");
}
} else if (this.type === "gamedig") {
try {
const state = await Gamedig.query({
type: this.game,
host: this.hostname,
port: this.port,
givenPortOnly: true,
});
bean.msg = state.name;
bean.status = UP;
bean.ping = state.ping;
} catch (e) {
throw new Error(e.message);
}
} else if (this.type === "docker") {
log.debug(`[${this.name}] Prepare Options for Axios`);
log.debug("monitor", `[${this.name}] Prepare Options for Axios`);
const dockerHost = await R.load("docker_host", this.docker_host);
const options = {
url: `/containers/${this.docker_container}/json`,
timeout: this.interval * 1000 * 0.8,
headers: {
"Accept": "*/*",
"User-Agent": "Uptime-Kuma/" + version,
},
httpsAgent: new https.Agent({
httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: ! this.getIgnoreTls(),
rejectUnauthorized: !this.getIgnoreTls(),
}),
httpAgent: CacheableDnsHttpAgent.getHttpAgent({
maxCachedSessions: 0,
}),
};
@@ -509,7 +616,7 @@ class Monitor extends BeanModel {
options.baseURL = DockerHost.patchDockerURL(dockerHost._dockerDaemon);
}
log.debug(`[${this.name}] Axios Request`);
log.debug("monitor", `[${this.name}] Axios Request`);
let res = await axios.request(options);
if (res.data.State.Running) {
bean.status = UP;
@@ -575,11 +682,18 @@ class Monitor extends BeanModel {
} else if (this.type === "mysql") {
let startTime = dayjs().valueOf();
await mysqlQuery(this.databaseConnectionString, this.databaseQuery);
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery);
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "mongodb") {
let startTime = dayjs().valueOf();
await mongodbPing(this.databaseConnectionString);
bean.msg = "";
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "radius") {
let startTime = dayjs().valueOf();
@@ -616,9 +730,23 @@ class Monitor extends BeanModel {
}
}
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "redis") {
let startTime = dayjs().valueOf();
bean.msg = await redisPingAsync(this.databaseConnectionString);
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type in UptimeKumaServer.monitorTypeList) {
let startTime = dayjs().valueOf();
const monitorType = UptimeKumaServer.monitorTypeList[this.type];
await monitorType.check(this, bean);
if (!bean.ping) {
bean.ping = dayjs().valueOf() - startTime;
}
} else {
bean.msg = "Unknown Monitor Type";
bean.status = PENDING;
throw new Error("Unknown Monitor Type");
}
if (this.isUpsideDown()) {
@@ -708,7 +836,7 @@ class Monitor extends BeanModel {
await R.store(bean);
log.debug("monitor", `[${this.name}] prometheus.update`);
prometheus.update(bean, tlsInfo);
this.prometheus?.update(bean, tlsInfo);
previousBeat = bean;
@@ -766,7 +894,6 @@ class Monitor extends BeanModel {
domain: this.authDomain,
workstation: this.authWorkstation ? this.authWorkstation : undefined
});
} else {
res = await axios.request(options);
}
@@ -793,15 +920,15 @@ class Monitor extends BeanModel {
clearTimeout(this.heartbeatInterval);
this.isStop = true;
this.prometheus().remove();
this.prometheus?.remove();
}
/**
* Get a new prometheus instance
* @returns {Prometheus}
* Get prometheus instance
* @returns {Prometheus|undefined}
*/
prometheus() {
return new Prometheus(this);
getPrometheus() {
return this.prometheus;
}
/**
@@ -1095,12 +1222,18 @@ class Monitor extends BeanModel {
for (let notification of notificationList) {
try {
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
const heartbeatJSON = bean.toJSON();
// Prevent if the msg is undefined, notifications such as Discord cannot send out.
if (!heartbeatJSON["msg"]) {
heartbeatJSON["msg"] = "N/A";
}
// Also provide the time in server timezone
heartbeatJSON["timezone"] = await UptimeKumaServer.getInstance().getTimezone();
heartbeatJSON["timezoneOffset"] = UptimeKumaServer.getInstance().getTimezoneOffset();
heartbeatJSON["localDateTime"] = dayjs.utc(heartbeatJSON["time"]).tz(heartbeatJSON["timezone"]).format(SQL_DATETIME_FORMAT);
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), heartbeatJSON);
} catch (e) {
log.error("monitor", "Cannot send notification to " + notification.name);
@@ -1123,13 +1256,19 @@ class Monitor extends BeanModel {
}
/**
* Send notification about a certificate
* checks certificate chain for expiring certificates
* @param {Object} tlsInfoObject Information about certificate
*/
async sendCertNotification(tlsInfoObject) {
async checkCertExpiryNotifications(tlsInfoObject) {
if (tlsInfoObject && tlsInfoObject.certInfo && tlsInfoObject.certInfo.daysRemaining) {
const notificationList = await Monitor.getNotificationList(this);
if (! notificationList.length > 0) {
// fail fast. If no notification is set, all the following checks can be skipped.
log.debug("monitor", "No notification, no need to send cert notification");
return;
}
let notifyDays = await setting("tlsExpiryNotifyDays");
if (notifyDays == null || !Array.isArray(notifyDays)) {
// Reset Default
@@ -1137,10 +1276,19 @@ class Monitor extends BeanModel {
notifyDays = [ 7, 14, 21 ];
}
if (notifyDays != null && Array.isArray(notifyDays)) {
for (const day of notifyDays) {
log.debug("monitor", "call sendCertNotificationByTargetDays", day);
await this.sendCertNotificationByTargetDays(tlsInfoObject.certInfo.daysRemaining, day, notificationList);
if (Array.isArray(notifyDays)) {
for (const targetDays of notifyDays) {
let certInfo = tlsInfoObject.certInfo;
while (certInfo) {
let subjectCN = certInfo.subject["CN"];
if (certInfo.daysRemaining > targetDays) {
log.debug("monitor", `No need to send cert notification for ${certInfo.certType} certificate "${subjectCN}" (${certInfo.daysRemaining} days valid) on ${targetDays} deadline.`);
} else {
log.debug("monitor", `call sendCertNotificationByTargetDays for ${targetDays} deadline on certificate ${subjectCN}.`);
await this.sendCertNotificationByTargetDays(subjectCN, certInfo.certType, certInfo.daysRemaining, targetDays, notificationList);
}
certInfo = certInfo.issuerCertificate;
}
}
}
}
@@ -1149,55 +1297,47 @@ class Monitor extends BeanModel {
/**
* Send a certificate notification when certificate expires in less
* than target days
* @param {number} daysRemaining Number of days remaining on certifcate
* @param {string} certCN Common Name attribute from the certificate subject
* @param {string} certType certificate type
* @param {number} daysRemaining Number of days remaining on certificate
* @param {number} targetDays Number of days to alert after
* @param {LooseObject<any>[]} notificationList List of notification providers
* @returns {Promise<void>}
*/
async sendCertNotificationByTargetDays(daysRemaining, targetDays, notificationList) {
async sendCertNotificationByTargetDays(certCN, certType, daysRemaining, targetDays, notificationList) {
if (daysRemaining > targetDays) {
log.debug("monitor", `No need to send cert notification. ${daysRemaining} > ${targetDays}`);
let row = await R.getRow("SELECT * FROM notification_sent_history WHERE type = ? AND monitor_id = ? AND days <= ?", [
"certificate",
this.id,
targetDays,
]);
// Sent already, no need to send again
if (row) {
log.debug("monitor", "Sent already, no need to send again");
return;
}
if (notificationList.length > 0) {
let sent = false;
log.debug("monitor", "Send certificate notification");
let row = await R.getRow("SELECT * FROM notification_sent_history WHERE type = ? AND monitor_id = ? AND days = ?", [
for (let notification of notificationList) {
try {
log.debug("monitor", "Sending to " + notification.name);
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] ${certType} certificate ${certCN} will be expired in ${daysRemaining} days`);
sent = true;
} catch (e) {
log.error("monitor", "Cannot send cert notification to " + notification.name);
log.error("monitor", e);
}
}
if (sent) {
await R.exec("INSERT INTO notification_sent_history (type, monitor_id, days) VALUES(?, ?, ?)", [
"certificate",
this.id,
targetDays,
]);
// Sent already, no need to send again
if (row) {
log.debug("monitor", "Sent already, no need to send again");
return;
}
let sent = false;
log.debug("monitor", "Send certificate notification");
for (let notification of notificationList) {
try {
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) {
log.error("monitor", "Cannot send cert notification to " + notification.name);
log.error("monitor", e);
}
}
if (sent) {
await R.exec("INSERT INTO notification_sent_history (type, monitor_id, days) VALUES(?, ?, ?)", [
"certificate",
this.id,
targetDays,
]);
}
} else {
log.debug("monitor", "No notification, no need to send cert notification");
}
}
@@ -1208,7 +1348,7 @@ class Monitor extends BeanModel {
*/
static async getPreviousHeartbeat(monitorID) {
return await R.getRow(`
SELECT status, time FROM heartbeat
SELECT ping, status, time FROM heartbeat
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
`, [
monitorID
@@ -1221,18 +1361,24 @@ class Monitor extends BeanModel {
* @returns {Promise<boolean>}
*/
static async isUnderMaintenance(monitorID) {
let activeCondition = Maintenance.getActiveMaintenanceSQLCondition();
const maintenance = await R.getRow(`
SELECT COUNT(*) AS count
FROM monitor_maintenance mm
JOIN maintenance
ON mm.maintenance_id = maintenance.id
AND mm.monitor_id = ?
LEFT JOIN maintenance_timeslot
ON maintenance_timeslot.maintenance_id = maintenance.id
WHERE ${activeCondition}
LIMIT 1`, [ monitorID ]);
return maintenance.count !== 0;
const maintenanceIDList = await R.getCol(`
SELECT maintenance_id FROM monitor_maintenance
WHERE monitor_id = ?
`, [ monitorID ]);
for (const maintenanceID of maintenanceIDList) {
const maintenance = await UptimeKumaServer.getInstance().getMaintenance(maintenanceID);
if (maintenance && await maintenance.isUnderMaintenance()) {
return true;
}
}
const parent = await Monitor.getParent(monitorID);
if (parent != null) {
return await Monitor.isUnderMaintenance(parent.id);
}
return false;
}
/** Make sure monitor interval is between bounds */
@@ -1244,6 +1390,94 @@ class Monitor extends BeanModel {
throw new Error(`Interval cannot be less than ${MIN_INTERVAL_SECOND} seconds`);
}
}
/**
* Gets Parent of the monitor
* @param {number} monitorID ID of monitor to get
* @returns {Promise<LooseObject<any>>}
*/
static async getParent(monitorID) {
return await R.getRow(`
SELECT parent.* FROM monitor parent
LEFT JOIN monitor child
ON child.parent = parent.id
WHERE child.id = ?
`, [
monitorID,
]);
}
/**
* Gets all Children of the monitor
* @param {number} monitorID ID of monitor to get
* @returns {Promise<LooseObject<any>>}
*/
static async getChildren(monitorID) {
return await R.getAll(`
SELECT * FROM monitor
WHERE parent = ?
`, [
monitorID,
]);
}
/**
* Gets Full Path-Name (Groups and Name)
* @returns {Promise<String>}
*/
async getPathName() {
let path = this.name;
if (this.parent === null) {
return path;
}
let parent = await Monitor.getParent(this.id);
while (parent !== null) {
path = `${parent.name} / ${path}`;
parent = await Monitor.getParent(parent.id);
}
return path;
}
/**
* Gets recursive all child ids
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<Array>}
*/
static async getAllChildrenIDs(monitorID) {
const childs = await Monitor.getChildren(monitorID);
if (childs === null) {
return [];
}
let childrenIDs = [];
for (const child of childs) {
childrenIDs.push(child.id);
childrenIDs = childrenIDs.concat(await Monitor.getAllChildrenIDs(child.id));
}
return childrenIDs;
}
/**
* Checks recursive if parent (ancestors) are active
* @param {number} monitorID ID of the monitor to get
* @returns {Promise<Boolean>}
*/
static async isParentActive(monitorID) {
const parent = await Monitor.getParent(monitorID);
if (parent === null) {
return true;
}
const parentActive = await Monitor.isParentActive(parent.id);
return parent.active && parentActive;
}
}
module.exports = Monitor;

View File

@@ -3,7 +3,7 @@ const { R } = require("redbean-node");
const cheerio = require("cheerio");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const jsesc = require("jsesc");
const Maintenance = require("./maintenance");
const googleAnalytics = require("../google-analytics");
class StatusPage extends BeanModel {
@@ -53,9 +53,17 @@ class StatusPage extends BeanModel {
const head = $("head");
if (statusPage.googleAnalyticsTagId) {
let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.googleAnalyticsTagId);
head.append($(escapedGoogleAnalyticsScript));
}
// OG Meta Tags
head.append(`<meta property="og:title" content="${statusPage.title}" />`);
head.append(`<meta property="og:description" content="${description155}" />`);
let ogTitle = $("<meta property=\"og:title\" content=\"\" />").attr("content", statusPage.title);
head.append(ogTitle);
let ogDescription = $("<meta property=\"og:description\" content=\"\" />").attr("content", description155);
head.append(ogDescription);
// Preload data
// Add jsesc, fix https://github.com/louislam/uptime-kuma/issues/2186
@@ -225,6 +233,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id,
};
}
@@ -245,6 +254,7 @@ class StatusPage extends BeanModel {
customCSS: this.custom_css,
footerText: this.footer_text,
showPoweredBy: !!this.show_powered_by,
googleAnalyticsId: this.google_analytics_tag_id,
};
}
@@ -279,21 +289,17 @@ class StatusPage extends BeanModel {
try {
const publicMaintenanceList = [];
let activeCondition = Maintenance.getActiveMaintenanceSQLCondition();
let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(`
SELECT DISTINCT maintenance.*
FROM maintenance
JOIN maintenance_status_page
ON maintenance_status_page.maintenance_id = maintenance.id
AND maintenance_status_page.status_page_id = ?
LEFT JOIN maintenance_timeslot
ON maintenance_timeslot.maintenance_id = maintenance.id
WHERE ${activeCondition}
ORDER BY maintenance.end_date
`, [ statusPageId ]));
let maintenanceIDList = await R.getCol(`
SELECT DISTINCT maintenance_id
FROM maintenance_status_page
WHERE status_page_id = ?
`, [ statusPageId ]);
for (const bean of maintenanceBeanList) {
publicMaintenanceList.push(await bean.toPublicJSON());
for (const maintenanceID of maintenanceIDList) {
let maintenance = UptimeKumaServer.getInstance().getMaintenance(maintenanceID);
if (maintenance && await maintenance.isUnderMaintenance()) {
publicMaintenanceList.push(await maintenance.toPublicJSON());
}
}
return publicMaintenanceList;

View File

@@ -0,0 +1,19 @@
class MonitorType {
name = undefined;
/**
*
* @param {Monitor} monitor
* @param {Heartbeat} heartbeat
* @returns {Promise<void>}
*/
async check(monitor, heartbeat) {
throw new Error("You need to override check()");
}
}
module.exports = {
MonitorType,
};

View File

@@ -8,7 +8,6 @@ class ClickSendSMS extends NotificationProvider {
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
console.log({ notification });
let config = {
headers: {
"Content-Type": "application/json",

View File

@@ -15,7 +15,7 @@ class DingDing extends NotificationProvider {
msgtype: "markdown",
markdown: {
title: `[${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]}`,
text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n > ${heartbeatJSON["msg"]} \n > Time(UTC):${heartbeatJSON["time"]}`,
text: `## [${this.statusToString(heartbeatJSON["status"])}] ${monitorJSON["name"]} \n> ${heartbeatJSON["msg"]}\n> Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
}
};
if (this.sendToDingDing(notification, params)) {

View File

@@ -59,8 +59,8 @@ class Discord extends NotificationProvider {
value: monitorJSON["type"] === "push" ? "Heartbeat" : address,
},
{
name: "Time (UTC)",
value: heartbeatJSON["time"],
name: `Time (${heartbeatJSON["timezone"]})`,
value: heartbeatJSON["localDateTime"],
},
{
name: "Error",
@@ -94,8 +94,8 @@ class Discord extends NotificationProvider {
value: monitorJSON["type"] === "push" ? "Heartbeat" : address,
},
{
name: "Time (UTC)",
value: heartbeatJSON["time"],
name: `Time (${heartbeatJSON["timezone"]})`,
value: heartbeatJSON["localDateTime"],
},
{
name: "Ping",

View File

@@ -35,8 +35,7 @@ class Feishu extends NotificationProvider {
text:
"[Down] " +
heartbeatJSON["msg"] +
"\nTime (UTC): " +
heartbeatJSON["time"],
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
},
],
],
@@ -62,8 +61,7 @@ class Feishu extends NotificationProvider {
text:
"[Up] " +
heartbeatJSON["msg"] +
"\nTime (UTC): " +
heartbeatJSON["time"],
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
},
],
],

View File

@@ -33,7 +33,10 @@ class Line extends NotificationProvider {
"messages": [
{
"type": "text",
"text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
"text": "UptimeKuma Alert: [🔴 Down]\n" +
"Name: " + monitorJSON["name"] + " \n" +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
}
]
};
@@ -44,7 +47,10 @@ class Line extends NotificationProvider {
"messages": [
{
"type": "text",
"text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
"text": "UptimeKuma Alert: [✅ Up]\n" +
"Name: " + monitorJSON["name"] + " \n" +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
}
]
};

View File

@@ -24,12 +24,18 @@ class LineNotify extends NotificationProvider {
await axios.post(lineAPIUrl, qs.stringify(testMessage), config);
} else if (heartbeatJSON["status"] === DOWN) {
let downMessage = {
"message": "\n[🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
"message": "\n[🔴 Down]\n" +
"Name: " + monitorJSON["name"] + " \n" +
heartbeatJSON["msg"] + "\n" +
`Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lineAPIUrl, qs.stringify(downMessage), config);
} else if (heartbeatJSON["status"] === UP) {
let upMessage = {
"message": "\n[✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
"message": "\n[✅ Up]\n" +
"Name: " + monitorJSON["name"] + " \n" +
heartbeatJSON["msg"] + "\n" +
`Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lineAPIUrl, qs.stringify(upMessage), config);
}

View File

@@ -8,7 +8,12 @@ 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 lunaseaurl = "";
if (notification.lunaseaTarget === "user") {
lunaseaurl = "https://notify.lunasea.app/v1/custom/user/" + notification.lunaseaUserID;
} else {
lunaseaurl = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice;
}
try {
if (heartbeatJSON == null) {
@@ -16,25 +21,29 @@ class LunaSea extends NotificationProvider {
"title": "Uptime Kuma Alert",
"body": msg,
};
await axios.post(lunaseadevice, testdata);
await axios.post(lunaseaurl, testdata);
return okMsg;
}
if (heartbeatJSON["status"] === DOWN) {
let downdata = {
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
"body": "[🔴 Down] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lunaseadevice, downdata);
await axios.post(lunaseaurl, downdata);
return okMsg;
}
if (heartbeatJSON["status"] === UP) {
let updata = {
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
"body": "[✅ Up] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`
};
await axios.post(lunaseadevice, updata);
await axios.post(lunaseaurl, updata);
return okMsg;
}

View File

@@ -10,7 +10,7 @@ class Mattermost extends NotificationProvider {
let okMsg = "Sent Successfully.";
try {
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
// If heartbeatJSON is null, assume we're testing.
// If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing.
if (heartbeatJSON == null) {
let mattermostTestData = {
username: mattermostUserName,
@@ -27,97 +27,79 @@ class Mattermost extends NotificationProvider {
}
const mattermostIconEmoji = notification.mattermosticonemo;
const mattermostIconUrl = notification.mattermosticonurl;
let mattermostIconEmojiOnline = "";
let mattermostIconEmojiOffline = "";
if (heartbeatJSON["status"] === DOWN) {
let mattermostdowndata = {
username: mattermostUserName,
text: "Uptime Kuma Alert",
channel: mattermostChannel,
icon_emoji: mattermostIconEmoji,
icon_url: mattermostIconUrl,
attachments: [
{
fallback:
"Your " +
monitorJSON["name"] +
" service went down.",
color: "#FF0000",
title:
"❌ " +
monitorJSON["name"] +
" service went down. ❌",
title_link: monitorJSON["url"],
fields: [
{
short: true,
title: "Service Name",
value: monitorJSON["name"],
},
{
short: true,
title: "Time (UTC)",
value: heartbeatJSON["time"],
},
{
short: false,
title: "Error",
value: heartbeatJSON["msg"],
},
],
},
],
};
await axios.post(
notification.mattermostWebhookUrl,
mattermostdowndata
);
return okMsg;
} else if (heartbeatJSON["status"] === UP) {
let mattermostupdata = {
username: mattermostUserName,
text: "Uptime Kuma Alert",
channel: mattermostChannel,
icon_emoji: mattermostIconEmoji,
icon_url: mattermostIconUrl,
attachments: [
{
fallback:
"Your " +
monitorJSON["name"] +
" service went up!",
color: "#32CD32",
title:
"✅ " +
monitorJSON["name"] +
" service went up! ✅",
title_link: monitorJSON["url"],
fields: [
{
short: true,
title: "Service Name",
value: monitorJSON["name"],
},
{
short: true,
title: "Time (UTC)",
value: heartbeatJSON["time"],
},
{
short: false,
title: "Ping",
value: heartbeatJSON["ping"] + "ms",
},
],
},
],
};
await axios.post(
notification.mattermostWebhookUrl,
mattermostupdata
);
return okMsg;
if (mattermostIconEmoji && typeof mattermostIconEmoji === "string") {
const emojiArray = mattermostIconEmoji.split(" ");
if (emojiArray.length >= 2) {
mattermostIconEmojiOnline = emojiArray[0];
mattermostIconEmojiOffline = emojiArray[1];
}
}
const mattermostIconUrl = notification.mattermosticonurl;
let iconEmoji = mattermostIconEmoji;
let statusField = {
short: false,
title: "Error",
value: heartbeatJSON.msg,
};
let statusText = "unknown";
let color = "#000000";
if (heartbeatJSON.status === DOWN) {
iconEmoji = mattermostIconEmojiOffline || mattermostIconEmoji;
statusField = {
short: false,
title: "Error",
value: heartbeatJSON.msg,
};
statusText = "down.";
color = "#FF0000";
} else if (heartbeatJSON.status === UP) {
iconEmoji = mattermostIconEmojiOnline || mattermostIconEmoji;
statusField = {
short: false,
title: "Ping",
value: heartbeatJSON.ping + "ms",
};
statusText = "up!";
color = "#32CD32";
}
let mattermostdata = {
username: monitorJSON.name + " " + mattermostUserName,
channel: mattermostChannel,
icon_emoji: iconEmoji,
icon_url: mattermostIconUrl,
attachments: [
{
fallback:
"Your " +
monitorJSON.name +
" service went " +
statusText,
color: color,
title:
monitorJSON.name +
" service went " +
statusText,
title_link: monitorJSON.url,
fields: [
statusField,
{
short: true,
title: `Time (${heartbeatJSON["timezone"]})`,
value: heartbeatJSON.localDateTime,
},
],
},
],
};
await axios.post(
notification.mattermostWebhookUrl,
mattermostdata
);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}

View File

@@ -1,5 +1,6 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { DOWN, UP } = require("../../src/util");
class Ntfy extends NotificationProvider {
@@ -9,16 +10,54 @@ class Ntfy extends NotificationProvider {
let okMsg = "Sent Successfully.";
try {
let headers = {};
if (notification.ntfyusername) {
if (notification.ntfyAuthenticationMethod === "usernamePassword") {
headers = {
"Authorization": "Basic " + Buffer.from(notification.ntfyusername + ":" + notification.ntfypassword).toString("base64"),
};
} else if (notification.ntfyAuthenticationMethod === "accessToken") {
headers = {
"Authorization": "Bearer " + notification.ntfyaccesstoken,
};
}
// If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing.
if (heartbeatJSON == null) {
let ntfyTestData = {
"topic": notification.ntfytopic,
"title": (monitorJSON?.name || notification.ntfytopic) + " [Uptime-Kuma]",
"message": msg,
"priority": notification.ntfyPriority,
"tags": [ "test_tube" ],
};
await axios.post(`${notification.ntfyserverurl}`, ntfyTestData, { headers: headers });
return okMsg;
}
let tags = [];
let status = "unknown";
let priority = notification.ntfyPriority || 4;
if ("status" in heartbeatJSON) {
if (heartbeatJSON.status === DOWN) {
tags = [ "red_circle" ];
status = "Down";
// if priority is not 5, increase priority for down alerts
priority = priority === 5 ? priority : priority + 1;
} else if (heartbeatJSON["status"] === UP) {
tags = [ "green_circle" ];
status = "Up";
}
}
let data = {
"topic": notification.ntfytopic,
"message": msg,
"priority": notification.ntfyPriority || 4,
"title": "Uptime-Kuma",
"message": heartbeatJSON.msg,
"priority": priority,
"title": monitorJSON.name + " " + status + " [Uptime-Kuma]",
"tags": tags,
"actions": [
{
"action": "view",
"label": "Open " + monitorJSON.name,
"url": monitorJSON.url,
}
]
};
if (notification.ntfyIcon) {

View File

@@ -0,0 +1,97 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP, DOWN } = require("../../src/util");
const opsgenieAlertsUrlEU = "https://api.eu.opsgenie.com/v2/alerts";
const opsgenieAlertsUrlUS = "https://api.opsgenie.com/v2/alerts";
let okMsg = "Sent Successfully.";
class Opsgenie extends NotificationProvider {
name = "Opsgenie";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let opsgenieAlertsUrl;
let priority = (!notification.opsgeniePriority) ? 3 : notification.opsgeniePriority;
const textMsg = "Uptime Kuma Alert";
try {
switch (notification.opsgenieRegion) {
case "US":
opsgenieAlertsUrl = opsgenieAlertsUrlUS;
break;
case "EU":
opsgenieAlertsUrl = opsgenieAlertsUrlEU;
break;
default:
opsgenieAlertsUrl = opsgenieAlertsUrlUS;
}
if (heartbeatJSON == null) {
let notificationTestAlias = "uptime-kuma-notification-test";
let data = {
"message": msg,
"alias": notificationTestAlias,
"source": "Uptime Kuma",
"priority": "P5"
};
return this.post(notification, opsgenieAlertsUrl, data);
}
if (heartbeatJSON.status === DOWN) {
let data = {
"message": monitorJSON ? textMsg + `: ${monitorJSON.name}` : textMsg,
"alias": monitorJSON.name,
"description": msg,
"source": "Uptime Kuma",
"priority": `P${priority}`
};
return this.post(notification, opsgenieAlertsUrl, data);
}
if (heartbeatJSON.status === UP) {
let opsgenieAlertsCloseUrl = `${opsgenieAlertsUrl}/${encodeURIComponent(monitorJSON.name)}/close?identifierType=alias`;
let data = {
"source": "Uptime Kuma",
};
return this.post(notification, opsgenieAlertsCloseUrl, data);
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
*
* @param {BeanModel} notification
* @param {string} url Request url
* @param {Object} data Request body
* @returns {Promise<string>}
*/
async post(notification, url, data) {
let config = {
headers: {
"Content-Type": "application/json",
"Authorization": `GenieKey ${notification.opsgenieApiKey}`,
}
};
let res = await axios.post(url, data, config);
if (res.status == null) {
return "Opsgenie notification failed with invalid response!";
}
if (res.status < 200 || res.status >= 300) {
return `Opsgenie notification failed with status code ${res.status}`;
}
return okMsg;
}
}
module.exports = Opsgenie;

View File

@@ -0,0 +1,91 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
const { setting } = require("../util-server");
let successMessage = "Sent Successfully.";
class PagerTree extends NotificationProvider {
name = "PagerTree";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
if (heartbeatJSON == null) {
// general messages
return this.postNotification(notification, msg, monitorJSON, heartbeatJSON);
}
if (heartbeatJSON.status === UP && notification.pagertreeAutoResolve === "resolve") {
return this.postNotification(notification, null, monitorJSON, heartbeatJSON, notification.pagertreeAutoResolve);
}
if (heartbeatJSON.status === DOWN) {
const title = `Uptime Kuma Monitor "${monitorJSON.name}" is DOWN`;
return this.postNotification(notification, title, monitorJSON, heartbeatJSON);
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
* Check if result is successful, result code should be in range 2xx
* @param {Object} result Axios response object
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
if (result.status == null) {
throw new Error("PagerTree notification failed with invalid response!");
}
if (result.status < 200 || result.status >= 300) {
throw new Error("PagerTree notification failed with status code " + result.status);
}
}
/**
* Send the message
* @param {BeanModel} notification Message title
* @param {string} title Message title
* @param {Object} monitorJSON Monitor details (For Up/Down only)
* @param {?string} eventAction Action event for PagerTree (create, resolve)
* @returns {string}
*/
async postNotification(notification, title, monitorJSON, heartbeatJSON, eventAction = "create") {
if (eventAction == null) {
return "No action required";
}
const options = {
method: "POST",
url: notification.pagertreeIntegrationUrl,
headers: { "Content-Type": "application/json" },
data: {
event_type: eventAction,
id: heartbeatJSON?.monitorID || "uptime-kuma",
title: title,
urgency: notification.pagertreeUrgency,
heartbeat: heartbeatJSON,
monitor: monitorJSON
}
};
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorJSON) {
options.client = "Uptime Kuma";
options.client_url = baseURL + getMonitorRelativeURL(monitorJSON.id);
}
let result = await axios.request(options);
this.checkResult(result);
if (result.statusText != null) {
return "PagerTree notification succeed: " + result.statusText;
}
return successMessage;
}
}
module.exports = PagerTree;

View File

@@ -29,14 +29,18 @@ class Pushbullet extends NotificationProvider {
let downData = {
"type": "note",
"title": "UptimeKuma Alert: " + monitorJSON["name"],
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
"body": "[🔴 Down] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
};
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"],
"body": "[✅ Up] " +
heartbeatJSON["msg"] +
`\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`,
};
await axios.post(pushbulletUrl, upData, config);
}

View File

@@ -10,7 +10,7 @@ class Pushover extends NotificationProvider {
let pushoverlink = "https://api.pushover.net/1/messages.json";
let data = {
"message": "<b>Message</b>:" + msg,
"message": msg,
"user": notification.pushoveruserkey,
"token": notification.pushoverapptoken,
"sound": notification.pushoversounds,
@@ -24,13 +24,16 @@ class Pushover extends NotificationProvider {
if (notification.pushoverdevice) {
data.device = notification.pushoverdevice;
}
if (notification.pushoverttl) {
data.ttl = notification.pushoverttl;
}
try {
if (heartbeatJSON == null) {
await axios.post(pushoverlink, data);
return okMsg;
} else {
data.message += "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"];
data.message += `\n<b>Time (${heartbeatJSON["timezone"]})</b>:${heartbeatJSON["localDateTime"]}`;
await axios.post(pushoverlink, data);
return okMsg;
}

View File

@@ -22,8 +22,6 @@ class RocketChat extends NotificationProvider {
return okMsg;
}
const time = heartbeatJSON["time"];
let data = {
"text": "Uptime Kuma Alert",
"channel": notification.rocketchannel,
@@ -31,7 +29,7 @@ class RocketChat extends NotificationProvider {
"icon_emoji": notification.rocketiconemo,
"attachments": [
{
"title": "Uptime Kuma Alert *Time (UTC)*\n" + time,
"title": `Uptime Kuma Alert *Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`,
"text": "*Message*\n" + msg,
}
]

View File

@@ -39,10 +39,9 @@ class Slack extends NotificationProvider {
return okMsg;
}
const time = heartbeatJSON["time"];
const textMsg = "Uptime Kuma Alert";
let data = {
"text": monitorJSON ? textMsg + `: ${monitorJSON.name}` : textMsg,
"text": `${textMsg}\n${msg}`,
"channel": notification.slackchannel,
"username": notification.slackusername,
"icon_emoji": notification.slackiconemo,
@@ -65,7 +64,7 @@ class Slack extends NotificationProvider {
},
{
"type": "mrkdwn",
"text": "*Time (UTC)*\n" + time,
"text": `*Time (${heartbeatJSON["timezone"]})*\n${heartbeatJSON["localDateTime"]}`,
}],
}
],

View File

@@ -91,7 +91,7 @@ class SMTP extends NotificationProvider {
let bodyTextContent = msg;
if (heartbeatJSON) {
bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`;
bodyTextContent = `${msg}\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`;
}
// send mail with defined transport object

View File

@@ -9,17 +9,27 @@ class Telegram extends NotificationProvider {
let okMsg = "Sent Successfully.";
try {
let params = {
chat_id: notification.telegramChatID,
text: msg,
disable_notification: notification.telegramSendSilently ?? false,
protect_content: notification.telegramProtectContent ?? false,
};
if (notification.telegramMessageThreadID) {
params.message_thread_id = notification.telegramMessageThreadID;
}
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
params: {
chat_id: notification.telegramChatID,
text: msg,
},
params: params,
});
return okMsg;
} catch (error) {
let msg = (error.response.data.description) ? error.response.data.description : "Error without description";
throw new Error(msg);
if (error.response && error.response.data && error.response.data.description) {
throw new Error(error.response.data.description);
} else {
throw new Error(error.message);
}
}
}
}

View File

@@ -0,0 +1,41 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Twilio extends NotificationProvider {
name = "twilio";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
let accountSID = notification.twilioAccountSID;
let authToken = notification.twilioAuthToken;
try {
let config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
"Authorization": "Basic " + Buffer.from(accountSID + ":" + authToken).toString("base64"),
}
};
let data = new URLSearchParams();
data.append("To", notification.twilioToNumber);
data.append("From", notification.twilioFromNumber);
data.append("Body", msg);
let url = "https://api.twilio.com/2010-04-01/Accounts/" + accountSID + "/Messages.json";
await axios.post(url, data, config);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Twilio;

View File

@@ -23,7 +23,9 @@ const Mattermost = require("./notification-providers/mattermost");
const Ntfy = require("./notification-providers/ntfy");
const Octopush = require("./notification-providers/octopush");
const OneBot = require("./notification-providers/onebot");
const Opsgenie = require("./notification-providers/opsgenie");
const PagerDuty = require("./notification-providers/pagerduty");
const PagerTree = require("./notification-providers/pagertree");
const PromoSMS = require("./notification-providers/promosms");
const Pushbullet = require("./notification-providers/pushbullet");
const PushDeer = require("./notification-providers/pushdeer");
@@ -40,6 +42,7 @@ const Stackfield = require("./notification-providers/stackfield");
const Teams = require("./notification-providers/teams");
const TechulusPush = require("./notification-providers/techulus-push");
const Telegram = require("./notification-providers/telegram");
const Twilio = require("./notification-providers/twilio");
const Splunk = require("./notification-providers/splunk");
const Webhook = require("./notification-providers/webhook");
const WeCom = require("./notification-providers/wecom");
@@ -82,7 +85,9 @@ class Notification {
new Ntfy(),
new Octopush(),
new OneBot(),
new Opsgenie(),
new PagerDuty(),
new PagerTree(),
new PromoSMS(),
new Pushbullet(),
new PushDeer(),
@@ -101,6 +106,7 @@ class Notification {
new Teams(),
new TechulusPush(),
new Telegram(),
new Twilio(),
new Splunk(),
new Webhook(),
new WeCom(),

13
server/plugin.js Normal file
View File

@@ -0,0 +1,13 @@
class Plugin {
async load() {
}
async unload() {
}
}
module.exports = {
Plugin,
};

256
server/plugins-manager.js Normal file
View File

@@ -0,0 +1,256 @@
const fs = require("fs");
const { log } = require("../src/util");
const path = require("path");
const axios = require("axios");
const { Git } = require("./git");
const childProcess = require("child_process");
class PluginsManager {
static disable = false;
/**
* Plugin List
* @type {PluginWrapper[]}
*/
pluginList = [];
/**
* Plugins Dir
*/
pluginsDir;
server;
/**
*
* @param {UptimeKumaServer} server
*/
constructor(server) {
this.server = server;
if (!PluginsManager.disable) {
this.pluginsDir = "./data/plugins/";
if (! fs.existsSync(this.pluginsDir)) {
fs.mkdirSync(this.pluginsDir, { recursive: true });
}
log.debug("plugin", "Scanning plugin directory");
let list = fs.readdirSync(this.pluginsDir);
this.pluginList = [];
for (let item of list) {
this.loadPlugin(item);
}
} else {
log.warn("PLUGIN", "Skip scanning plugin directory");
}
}
/**
* Install a Plugin
*/
async loadPlugin(name) {
log.info("plugin", "Load " + name);
let plugin = new PluginWrapper(this.server, this.pluginsDir + name);
try {
await plugin.load();
this.pluginList.push(plugin);
} catch (e) {
log.error("plugin", "Failed to load plugin: " + this.pluginsDir + name);
log.error("plugin", "Reason: " + e.message);
}
}
/**
* Download a Plugin
* @param {string} repoURL Git repo url
* @param {string} name Directory name, also known as plugin unique name
*/
downloadPlugin(repoURL, name) {
if (fs.existsSync(this.pluginsDir + name)) {
log.info("plugin", "Plugin folder already exists? Removing...");
fs.rmSync(this.pluginsDir + name, {
recursive: true
});
}
log.info("plugin", "Installing plugin: " + name + " " + repoURL);
let result = Git.clone(repoURL, this.pluginsDir, name);
log.info("plugin", "Install result: " + result);
}
/**
* Remove a plugin
* @param {string} name
*/
async removePlugin(name) {
log.info("plugin", "Removing plugin: " + name);
for (let plugin of this.pluginList) {
if (plugin.info.name === name) {
await plugin.unload();
// Delete the plugin directory
fs.rmSync(this.pluginsDir + name, {
recursive: true
});
this.pluginList.splice(this.pluginList.indexOf(plugin), 1);
return;
}
}
log.warn("plugin", "Plugin not found: " + name);
throw new Error("Plugin not found: " + name);
}
/**
* TODO: Update a plugin
* Only available for plugins which were downloaded from the official list
* @param pluginID
*/
updatePlugin(pluginID) {
}
/**
* Get the plugin list from server + local installed plugin list
* Item will be merged if the `name` is the same.
* @returns {Promise<[]>}
*/
async fetchPluginList() {
let remotePluginList;
try {
const res = await axios.get("https://uptime.kuma.pet/c/plugins.json");
remotePluginList = res.data.pluginList;
} catch (e) {
log.error("plugin", "Failed to fetch plugin list: " + e.message);
remotePluginList = [];
}
for (let plugin of this.pluginList) {
let find = false;
// Try to merge
for (let remotePlugin of remotePluginList) {
if (remotePlugin.name === plugin.info.name) {
find = true;
remotePlugin.installed = true;
remotePlugin.name = plugin.info.name;
remotePlugin.fullName = plugin.info.fullName;
remotePlugin.description = plugin.info.description;
remotePlugin.version = plugin.info.version;
break;
}
}
// Local plugin
if (!find) {
plugin.info.local = true;
remotePluginList.push(plugin.info);
}
}
// Sort Installed first, then sort by name
return remotePluginList.sort((a, b) => {
if (a.installed === b.installed) {
if (a.fullName < b.fullName) {
return -1;
}
if (a.fullName > b.fullName) {
return 1;
}
return 0;
} else if (a.installed) {
return -1;
} else {
return 1;
}
});
}
}
class PluginWrapper {
server = undefined;
pluginDir = undefined;
/**
* Must be an `new-able` class.
* @type {function}
*/
pluginClass = undefined;
/**
*
* @type {Plugin}
*/
object = undefined;
info = {};
/**
*
* @param {UptimeKumaServer} server
* @param {string} pluginDir
*/
constructor(server, pluginDir) {
this.server = server;
this.pluginDir = pluginDir;
}
async load() {
let indexFile = this.pluginDir + "/index.js";
let packageJSON = this.pluginDir + "/package.json";
log.info("plugin", "Installing dependencies");
if (fs.existsSync(indexFile)) {
// Install dependencies
let result = childProcess.spawnSync("npm", [ "install" ], {
cwd: this.pluginDir,
env: {
...process.env,
PLAYWRIGHT_BROWSERS_PATH: "../../browsers", // Special handling for read-browser-monitor
}
});
if (result.stdout) {
log.info("plugin", "Install dependencies result: " + result.stdout.toString("utf-8"));
} else {
log.warn("plugin", "Install dependencies result: no output");
}
this.pluginClass = require(path.join(process.cwd(), indexFile));
let pluginClassType = typeof this.pluginClass;
if (pluginClassType === "function") {
this.object = new this.pluginClass(this.server);
await this.object.load();
} else {
throw new Error("Invalid plugin, it does not export a class");
}
if (fs.existsSync(packageJSON)) {
this.info = require(path.join(process.cwd(), packageJSON));
} else {
this.info.fullName = this.pluginDir;
this.info.name = "[unknown]";
this.info.version = "[unknown-version]";
}
this.info.installed = true;
log.info("plugin", `${this.info.fullName} v${this.info.version} loaded`);
}
}
async unload() {
await this.object.unload();
}
}
module.exports = {
PluginsManager,
PluginWrapper
};

View File

@@ -132,6 +132,9 @@ class Proxy {
...httpAgentOptions,
...httpsAgentOptions,
...proxyOptions,
tls: {
rejectUnauthorized: httpsAgentOptions.rejectUnauthorized,
},
});
httpAgent = agent;

View File

@@ -54,6 +54,13 @@ const loginRateLimiter = new KumaRateLimiter({
errorMessage: "Too frequently, try again later."
});
const apiRateLimiter = new KumaRateLimiter({
tokensPerInterval: 60,
interval: "minute",
fireImmediately: true,
errorMessage: "Too frequently, try again later."
});
const twoFaRateLimiter = new KumaRateLimiter({
tokensPerInterval: 30,
interval: "minute",
@@ -63,5 +70,6 @@ const twoFaRateLimiter = new KumaRateLimiter({
module.exports = {
loginRateLimiter,
apiRateLimiter,
twoFaRateLimiter,
};

View File

@@ -1,14 +1,16 @@
let express = require("express");
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, send403 } = require("../util-server");
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, sendHttpError } = require("../util-server");
const { R } = require("redbean-node");
const apicache = require("../modules/apicache");
const Monitor = require("../model/monitor");
const dayjs = require("dayjs");
const { UP, MAINTENANCE, DOWN, flipStatus, log } = require("../../src/util");
const { UP, MAINTENANCE, DOWN, PENDING, flipStatus, log } = require("../../src/util");
const StatusPage = require("../model/status_page");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const { UptimeCacheList } = require("../uptime-cache-list");
const { makeBadge } = require("badge-maker");
const { badgeConstants } = require("../config");
const { Prometheus } = require("../prometheus");
let router = express.Router();
@@ -36,7 +38,7 @@ router.get("/api/push/:pushToken", async (request, response) => {
let pushToken = request.params.pushToken;
let msg = request.query.msg || "OK";
let ping = request.query.ping || null;
let ping = parseInt(request.query.ping) || null;
let statusString = request.query.status || "up";
let status = (statusString === "up") ? UP : DOWN;
@@ -86,7 +88,9 @@ router.get("/api/push/:pushToken", async (request, response) => {
await R.store(bean);
io.to(monitor.user_id).emit("heartbeat", bean.toJSON());
UptimeCacheList.clearCache(monitor.id);
Monitor.sendStats(io, monitor.id, monitor.user_id);
new Prometheus(monitor).update(bean, undefined);
response.json({
ok: true,
@@ -111,8 +115,12 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
label,
upLabel = "Up",
downLabel = "Down",
pendingLabel = "Pending",
maintenanceLabel = "Maintenance",
upColor = badgeConstants.defaultUpColor,
downColor = badgeConstants.defaultDownColor,
pendingColor = badgeConstants.defaultPendingColor,
maintenanceColor = badgeConstants.defaultMaintenanceColor,
style = badgeConstants.defaultStyle,
value, // for demo purpose only
} = request.query;
@@ -139,11 +147,34 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
badgeValues.color = badgeConstants.naColor;
} else {
const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId);
const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1;
const state = overrideValue !== undefined ? overrideValue : heartbeat.status;
badgeValues.label = label ? label : "";
badgeValues.color = state ? upColor : downColor;
badgeValues.message = label ?? state ? upLabel : downLabel;
if (label === undefined) {
badgeValues.label = "Status";
} else {
badgeValues.label = label;
}
switch (state) {
case DOWN:
badgeValues.color = downColor;
badgeValues.message = downLabel;
break;
case UP:
badgeValues.color = upColor;
badgeValues.message = upLabel;
break;
case PENDING:
badgeValues.color = pendingColor;
badgeValues.message = pendingLabel;
break;
case MAINTENANCE:
badgeValues.color = maintenanceColor;
badgeValues.message = maintenanceLabel;
break;
default:
badgeValues.color = badgeConstants.naColor;
badgeValues.message = "N/A";
}
}
// build the svg based on given values
@@ -152,7 +183,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});
@@ -189,7 +220,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
const badgeValues = { style };
if (!publicMonitor) {
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
@@ -199,15 +230,18 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
);
// limit the displayed uptime percentage to four (two, when displayed as percent) decimal digits
const cleanUptime = parseFloat(uptime.toPrecision(4));
const cleanUptime = (uptime * 100).toPrecision(4);
// use a given, custom color or calculate one based on the uptime value
badgeValues.color = color ?? percentageToColor(uptime);
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a lable string. If a custom label is given, override the default one (requestedDuration)
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
badgeValues.message = filterAndJoin([ prefix, `${cleanUptime * 100}`, suffix ]);
// build a label string. If a custom label is given, override the default one (requestedDuration)
badgeValues.label = filterAndJoin([
labelPrefix,
label ?? `Uptime (${requestedDuration}${labelSuffix})`,
]);
badgeValues.message = filterAndJoin([ prefix, cleanUptime, suffix ]);
}
// build the SVG based on given values
@@ -216,7 +250,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});
@@ -267,7 +301,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a lable string. If a custom label is given, override the default one (requestedDuration)
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
badgeValues.label = filterAndJoin([ labelPrefix, label ?? `Avg. Ping (${requestedDuration}${labelSuffix})` ]);
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
}
@@ -277,7 +311,240 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});
router.get("/api/badge/:id/avg-response/:duration?", cache("5 minutes"), async (request, response) => {
allowAllOrigin(response);
const {
label,
labelPrefix,
labelSuffix,
prefix,
suffix = badgeConstants.defaultPingValueSuffix,
color = badgeConstants.defaultPingColor,
labelColor,
style = badgeConstants.defaultStyle,
value, // for demo purpose only
} = request.query;
try {
const requestedMonitorId = parseInt(request.params.id, 10);
// Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d)
const requestedDuration = Math.min(
request.params.duration
? parseInt(request.params.duration, 10)
: 24,
720
);
const overrideValue = value && parseFloat(value);
const publicAvgPing = parseInt(await R.getCell(`
SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat
WHERE monitor_group.group_id = \`group\`.id
AND heartbeat.time > DATETIME('now', ? || ' hours')
AND heartbeat.ping IS NOT NULL
AND public = 1
AND heartbeat.monitor_id = ?
`,
[ -requestedDuration, requestedMonitorId ]
));
const badgeValues = { style };
if (!publicAvgPing) {
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
const avgPing = parseInt(overrideValue ?? publicAvgPing);
badgeValues.color = color;
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a label string. If a custom label is given, override the default one (requestedDuration)
badgeValues.label = filterAndJoin([
labelPrefix,
label ?? `Avg. Response (${requestedDuration}h)`,
labelSuffix,
]);
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
}
// build the SVG based on given values
const svg = makeBadge(badgeValues);
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
sendHttpError(response, error.message);
}
});
router.get("/api/badge/:id/cert-exp", cache("5 minutes"), async (request, response) => {
allowAllOrigin(response);
const date = request.query.date;
const {
label,
labelPrefix,
labelSuffix,
prefix,
suffix = date ? "" : badgeConstants.defaultCertExpValueSuffix,
upColor = badgeConstants.defaultUpColor,
warnColor = badgeConstants.defaultWarnColor,
downColor = badgeConstants.defaultDownColor,
warnDays = badgeConstants.defaultCertExpireWarnDays,
downDays = badgeConstants.defaultCertExpireDownDays,
labelColor,
style = badgeConstants.defaultStyle,
value, // for demo purpose only
} = request.query;
try {
const requestedMonitorId = parseInt(request.params.id, 10);
const overrideValue = value && parseFloat(value);
let publicMonitor = await R.getRow(`
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
WHERE monitor_group.group_id = \`group\`.id
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
);
const badgeValues = { style };
if (!publicMonitor) {
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
const tlsInfoBean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
requestedMonitorId,
]);
if (!tlsInfoBean) {
// return a "No/Bad Cert" badge in naColor (grey), if no cert saved (does not save bad certs?)
badgeValues.message = "No/Bad Cert";
badgeValues.color = badgeConstants.naColor;
} else {
const tlsInfo = JSON.parse(tlsInfoBean.info_json);
if (!tlsInfo.valid) {
// return a "Bad Cert" badge in naColor (grey), when cert is not valid
badgeValues.message = "Bad Cert";
badgeValues.color = badgeConstants.downColor;
} else {
const daysRemaining = parseInt(overrideValue ?? tlsInfo.certInfo.daysRemaining);
if (daysRemaining > warnDays) {
badgeValues.color = upColor;
} else if (daysRemaining > downDays) {
badgeValues.color = warnColor;
} else {
badgeValues.color = downColor;
}
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a label string. If a custom label is given, override the default one
badgeValues.label = filterAndJoin([
labelPrefix,
label ?? "Cert Exp.",
labelSuffix,
]);
badgeValues.message = filterAndJoin([ prefix, date ? tlsInfo.certInfo.validTo : daysRemaining, suffix ]);
}
}
}
// build the SVG based on given values
const svg = makeBadge(badgeValues);
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
sendHttpError(response, error.message);
}
});
router.get("/api/badge/:id/response", cache("5 minutes"), async (request, response) => {
allowAllOrigin(response);
const {
label,
labelPrefix,
labelSuffix,
prefix,
suffix = badgeConstants.defaultPingValueSuffix,
color = badgeConstants.defaultPingColor,
labelColor,
style = badgeConstants.defaultStyle,
value, // for demo purpose only
} = request.query;
try {
const requestedMonitorId = parseInt(request.params.id, 10);
const overrideValue = value && parseFloat(value);
let publicMonitor = await R.getRow(`
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
WHERE monitor_group.group_id = \`group\`.id
AND monitor_group.monitor_id = ?
AND public = 1
`,
[ requestedMonitorId ]
);
const badgeValues = { style };
if (!publicMonitor) {
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non existent
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
const heartbeat = await Monitor.getPreviousHeartbeat(
requestedMonitorId
);
if (!heartbeat.ping) {
// return a "N/A" badge in naColor (grey), if previous heartbeat has no ping
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
} else {
const ping = parseInt(overrideValue ?? heartbeat.ping);
badgeValues.color = color;
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
badgeValues.labelColor = labelColor ?? "";
// build a label string. If a custom label is given, override the default one
badgeValues.label = filterAndJoin([
labelPrefix,
label ?? "Response",
labelSuffix,
]);
badgeValues.message = filterAndJoin([ prefix, ping, suffix ]);
}
}
// build the SVG based on given values
const svg = makeBadge(badgeValues);
response.type("image/svg+xml");
response.send(svg);
} catch (error) {
sendHttpError(response, error.message);
}
});

View File

@@ -2,7 +2,7 @@ let express = require("express");
const apicache = require("../modules/apicache");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const StatusPage = require("../model/status_page");
const { allowDevAllOrigin, send403 } = require("../util-server");
const { allowDevAllOrigin, sendHttpError } = require("../util-server");
const { R } = require("redbean-node");
const Monitor = require("../model/monitor");
@@ -44,10 +44,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons
let statusPageData = await StatusPage.getStatusPageData(statusPage);
if (!statusPageData) {
response.statusCode = 404;
response.json({
msg: "Not Found"
});
sendHttpError(response, "Not Found");
return;
}
@@ -55,7 +52,7 @@ router.get("/api/status-page/:slug", cache("5 minutes"), async (request, respons
response.json(statusPageData);
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});
@@ -103,7 +100,7 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
});
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});
@@ -119,10 +116,7 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
]);
if (!statusPage) {
response.statusCode = 404;
response.json({
msg: "Not Found"
});
sendHttpError(response, "Not Found");
return;
}
@@ -141,7 +135,7 @@ router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async
});
} catch (error) {
send403(response, error.message);
sendHttpError(response, error.message);
}
});

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