diff --git a/SECURITY.md b/SECURITY.md index 47f0786f..1271565a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,5 +10,6 @@ currently being supported with security updates. | 1.x.x | :white_check_mark: | ## Reporting a Vulnerability +Please report security issues to uptime@kuma.pet. -https://github.com/louislam/uptime-kuma/issues +Do not use the issue tracker or discuss it in the public as it will cause more damage. diff --git a/server/notification-providers/teams.js b/server/notification-providers/teams.js new file mode 100644 index 00000000..72409ffc --- /dev/null +++ b/server/notification-providers/teams.js @@ -0,0 +1,124 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const { DOWN, UP } = require("../../src/util"); + +class Teams extends NotificationProvider { + name = "teams"; + + _statusMessageFactory = (status, monitorName) => { + if (status === DOWN) { + return `🔴 Application [${monitorName}] went down`; + } else if (status === UP) { + return `✅ Application [${monitorName}] is back online`; + } + return "Notification"; + }; + + _getThemeColor = (status) => { + if (status === DOWN) { + return "ff0000"; + } + if (status === UP) { + return "00e804"; + } + return "008cff"; + }; + + _notificationPayloadFactory = ({ + status, + monitorMessage, + monitorName, + monitorUrl, + }) => { + const notificationMessage = this._statusMessageFactory( + status, + monitorName + ); + + const facts = []; + + if (monitorName) { + facts.push({ + name: "Monitor", + value: monitorName, + }); + } + + if (monitorUrl) { + facts.push({ + name: "URL", + value: monitorUrl, + }); + } + + return { + "@context": "https://schema.org/extensions", + "@type": "MessageCard", + themeColor: this._getThemeColor(status), + summary: notificationMessage, + sections: [ + { + activityImage: + "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + activityTitle: "**Uptime Kuma**", + }, + { + activityTitle: notificationMessage, + }, + { + activityTitle: "**Description**", + text: monitorMessage, + facts, + }, + ], + }; + }; + + _sendNotification = async (webhookUrl, payload) => { + await axios.post(webhookUrl, payload); + }; + + _handleGeneralNotification = (webhookUrl, msg) => { + const payload = this._notificationPayloadFactory({ + monitorMessage: msg + }); + + return this._sendNotification(webhookUrl, payload); + }; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully. "; + + try { + if (heartbeatJSON == null) { + await this._handleGeneralNotification(notification.webhookUrl, msg); + return okMsg; + } + + let url; + + if (monitorJSON["type"] === "port") { + url = monitorJSON["hostname"]; + if (monitorJSON["port"]) { + url += ":" + monitorJSON["port"]; + } + } else { + url = monitorJSON["url"]; + } + + const payload = this._notificationPayloadFactory({ + monitorMessage: heartbeatJSON.msg, + monitorName: monitorJSON.name, + monitorUrl: url, + status: heartbeatJSON.status, + }); + + await this._sendNotification(notification.webhookUrl, payload); + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = Teams; diff --git a/server/notification.js b/server/notification.js index 83dabc53..13447241 100644 --- a/server/notification.js +++ b/server/notification.js @@ -13,6 +13,7 @@ const RocketChat = require("./notification-providers/rocket-chat"); const Signal = require("./notification-providers/signal"); const Slack = require("./notification-providers/slack"); const SMTP = require("./notification-providers/smtp"); +const Teams = require("./notification-providers/teams"); const Telegram = require("./notification-providers/telegram"); const Webhook = require("./notification-providers/webhook"); @@ -28,6 +29,7 @@ class Notification { const list = [ new Apprise(), new Discord(), + new Teams(), new Gotify(), new Line(), new LunaSea(), diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 0db46a78..220ff8d7 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -17,6 +17,7 @@ + @@ -400,6 +401,8 @@ + +
@@ -449,6 +452,7 @@ import { ucfirst } from "../util.ts" import Confirm from "./Confirm.vue"; import HiddenInput from "./HiddenInput.vue"; import Telegram from "./notifications/Telegram.vue"; +import Teams from "./notifications/Teams.vue"; import SMTP from "./notifications/SMTP.vue"; export default { @@ -456,6 +460,7 @@ export default { Confirm, HiddenInput, Telegram, + Teams, SMTP, }, props: {}, diff --git a/src/components/notifications/Teams.vue b/src/components/notifications/Teams.vue new file mode 100644 index 00000000..748bf7ad --- /dev/null +++ b/src/components/notifications/Teams.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/i18n.js b/src/i18n.js index 0640a1ae..fe2612fb 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -13,6 +13,7 @@ import pl from "./languages/pl"; import ruRU from "./languages/ru-RU"; import sr from "./languages/sr"; import srLatn from "./languages/sr-latn"; +import trTR from "./languages/tr-TR"; import svSE from "./languages/sv-SE"; import zhCN from "./languages/zh-CN"; import zhHK from "./languages/zh-HK"; @@ -30,6 +31,7 @@ const languageList = { "sr": sr, "sr-latn": srLatn, "sv-SE": svSE, + "tr-TR": trTR, "ko-KR": koKR, "ru-RU": ruRU, "zh-CN": zhCN, diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index fcae9415..243c2157 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -157,4 +157,5 @@ export default { Indigo: "Indigo", Purple: "Lila", Pink: "Pink", + "Search...": "Suchen...", } diff --git a/src/languages/en.js b/src/languages/en.js index 4f88d304..a378ddcb 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -157,4 +157,5 @@ export default { Indigo: "Indigo", Purple: "Purple", Pink: "Pink", + "Search...": "Search...", } diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js index fc510434..89c33fd6 100644 --- a/src/languages/it-IT.js +++ b/src/languages/it-IT.js @@ -20,6 +20,10 @@ export default { clearEventsMsg: "Si è certi di voler eliminare tutti gli eventi per questo servizio?", clearHeartbeatsMsg: "Si è certi di voler eliminare tutti gli intervalli di controllo per questo servizio?", confirmClearStatisticsMsg: "Si è certi di voler eliminare TUTTE le statistiche?", + twoFAVerifyLabel: "Scrivi il token per verificare che l'autenticazione a due fattori funzioni", + tokenValidSettingsMsg: "Il token è valido! È ora possibile salvare le impostazioni.", + confirmEnableTwoFAMsg: "Si è certi di voler abilitare l'autenticazione a due fattori?", + confirmDisableTwoFAMsg: "Si è certi di voler disabilitare l'autenticazione a due fattori?", Settings: "Impostazioni", Dashboard: "Cruscotto", "New Update": "Nuovo Aggiornamento Disponibile", @@ -117,7 +121,7 @@ export default { respTime: "Tempo di Risposta (ms)", notAvailableShort: "N/D", "Default enabled": "Abilitato di default", - "Also apply to existing monitors": "Applica anche ai monitoraggi esistenti", + "Apply on all existing monitors": "Applica su tutti i monitoraggi", Create: "Crea", "Clear Data": "Cancella dati", Events: "Eventi", @@ -128,20 +132,30 @@ export default { backupDescription3: "Dati sensibili come i token di autenticazione saranno inclusi nel backup, tenere quindi in un luogo sicuro.", alertNoFile: "Selezionare il file da importare.", alertWrongFileType: "Selezionare un file JSON.", - "Clear all statistics": "Pulisci tutte le statistiche", - twoFAVerifyLabel: "Please type in your token to verify that 2FA is working", - tokenValidSettingsMsg: "Token is valid! You can now save the 2FA settings.", - confirmEnableTwoFAMsg: "Are you sure you want to enable 2FA?", - confirmDisableTwoFAMsg: "Are you sure you want to disable 2FA?", - "Apply on all existing monitors": "Apply on all existing monitors", - "Verify Token": "Verify Token", - "Setup 2FA": "Setup 2FA", - "Enable 2FA": "Enable 2FA", - "Disable 2FA": "Disable 2FA", - "2FA Settings": "2FA Settings", - "Two Factor Authentication": "Two Factor Authentication", - Active: "Active", - Inactive: "Inactive", + "Verify Token": "Verifica Token", + "Setup 2FA": "Imposta l'autenticazione a due fattori", + "Enable 2FA": "Abilita l'autenticazione a due fattori", + "Disable 2FA": "Disabilita l'autenticazione a due fattori", + "2FA Settings": "Impostazioni autenticazione a due fattori", + "Two Factor Authentication": "Autenticazione a due fattori", + Active: "Attivata", + Inactive: "Disattivata", Token: "Token", - "Show URI": "Show URI", + "Show URI": "Mostra URI", + "Clear all statistics": "Pulisci tutte le statistiche", + Tags: "Etichette", + "Add New below or Select...": "Aggiungine una oppure scegli...", + "Tag with this name already exist.": "Un'etichetta con questo nome già esiste.", + "Tag with this value already exist.": "Un'etichetta con questo valore già esiste.", + color: "colori", + "value (optional)": "valore (opzionale)", + Gray: "Grigio", + Red: "Rosso", + Orange: "Arancione", + Green: "Verde", + Blue: "Blu", + Indigo: "Indigo", + Purple: "Viola", + Pink: "Rosa", + "Search...": "Cerca...", } diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js new file mode 100644 index 00000000..e05af23e --- /dev/null +++ b/src/languages/tr-TR.js @@ -0,0 +1,120 @@ +export default { + languageName: "Türkçe", + checkEverySecond: "{0} Saniyede bir kontrol et.", + "Avg.": "Ortalama", + retriesDescription: "Servisin kapalı olarak işaretlenmeden ve bir bildirim gönderilmeden önce maksimum yeniden deneme sayısı", + ignoreTLSError: "HTTPS web siteleri için TLS/SSL hatasını yoksay", + upsideDownModeDescription: "Servisin durumunu tersine çevirir. Servis çalışıyorsa kapalı olarak işaretler.", + maxRedirectDescription: "İzlenecek maksimum yönlendirme sayısı. Yönlendirmeleri devre dışı bırakmak için 0'a ayarlayın.", + acceptedStatusCodesDescription: "Servisin çalıştığını hangi durum kodları belirlesin?", + passwordNotMatchMsg: "Şifre eşleşmiyor.", + notificationDescription: "Servislerin bildirim gönderebilmesi için bir bildirim yöntemi belirleyin.", + keywordDescription: "Anahtar kelimeyi düz html veya JSON yanıtında arayın ve büyük/küçük harfe duyarlıdır", + pauseDashboardHome: "Durdur", + deleteMonitorMsg: "Servisi silmek istediğinden emin misin?", + deleteNotificationMsg: "Bu bildirimi tüm servisler için silmek istediğinden emin misin?", + resoverserverDescription: "Cloudflare varsayılan sunucudur, çözümleyici sunucusunu istediğiniz zaman değiştirebilirsiniz.", + rrtypeDescription: "İzlemek istediğiniz servisin RR-Tipini seçin", + pauseMonitorMsg: "Durdurmak istediğinden emin misin?", + clearEventsMsg: "Bu servisin bütün kayıtlarını silmek istediğinden emin misin?", + clearHeartbeatsMsg: "Bu servis için tüm sağlık durumunu silmek istediğinden emin misin?", + confirmClearStatisticsMsg: "Tüm istatistikleri silmek istediğinden emin misin?", + Settings: "Ayarlar", + Dashboard: "Panel", + "New Update": "Yeni Güncelleme", + Language: "Dil", + Appearance: "Görünüm", + Theme: "Tema", + General: "Genel", + Version: "Versiyon", + "Check Update On GitHub": "GitHub'da Güncellemeyi Kontrol Edin", + List: "Liste", + Add: "Ekle", + "Add New Monitor": "Yeni Servis Ekle", + "Quick Stats": "Servis istatistikleri", + Up: "Normal", + Down: "Hatalı", + Pending: "Bekliyor", + Unknown: "Bilinmeyen", + Pause: "Durdur", + Name: "Servis ismi", + Status: "Durum", + DateTime: "Zaman", + Message: "Mesaj", + "No important events": "Önemli olay yok", + Resume: "Devam et", + Edit: "Düzenle", + Delete: "Sil", + Current: "Şu anda", + Uptime: "Çalışma zamanı", + "Cert Exp.": "Sertifika Süresi", + days: "günler", + day: "gün", + "-day": "-gün", + hour: "saat", + "-hour": "-saat", + Response: "Cevap Süresi", + Ping: "Ping", + "Monitor Type": "Servis Tipi", + Keyword: "Anahtar Kelime", + "Friendly Name": "Panelde görünecek isim", + URL: "URL", + Hostname: "IP Adresi", + Port: "Port", + "Heartbeat Interval": "Servis Test Aralığı", + Retries: "Yeniden deneme", + Advanced: "Gelişmiş", + "Upside Down Mode": "Ters/Düz Modu", + "Max. Redirects": "Maksimum Yönlendirme", + "Accepted Status Codes": "Kabul Edilen Durum Kodları", + Save: "Kaydet", + Notifications: "Bildirimler", + "Not available, please setup.": "Atanmış bildirim yöntemi yok. Ayarlardan belirleyebilirsiniz.", + "Setup Notification": "Bildirim yöntemi kur", + Light: "Açık", + Dark: "Koyu", + Auto: "Oto", + "Theme - Heartbeat Bar": "Servis Bar Konumu", + Normal: "Normal", + Bottom: "Aşağıda", + None: "Gösterme", + Timezone: "Zaman Dilimi", + "Search Engine Visibility": "Arama Motoru Görünürlüğü", + "Allow indexing": "İndekslemeye izin ver", + "Discourage search engines from indexing site": "İndekslemeyi reddet", + "Change Password": "Şifre Değiştir", + "Current Password": "Şuan ki Şifre", + "New Password": "Yeni Şifre", + "Repeat New Password": "Yeni Şifreyi Tekrar Girin", + "Update Password": "Şifreyi Değiştir", + "Disable Auth": "Şifreli girişi iptal et.", + "Enable Auth": "Şifreli girişi aktif et.", + Logout: "Çıkış yap", + Leave: "Ayrıl", + "I understand, please disable": "Evet farkındayım, iptal et", + Confirm: "Onayla", + Yes: "Evet", + No: "Hayır", + Username: "Kullanıcı Adı", + Password: "Şifre", + "Remember me": "Beni Hatırla", + Login: "Giriş yap", + "No Monitors, please": "Servis yok, lütfen", + "add one": "bir servis ekleyin", + "Notification Type": "Bildirim Yöntemi", + Email: "E-mail", + Test: "Test", + "Certificate Info": "Sertifika Bilgisi", + "Resolver Server": "Çözümleyici Sunucu", + "Resource Record Type": "Kaynak Kayıt Türü", + "Last Result": "En son sonuçlar", + "Create your admin account": "Yönetici hesabınızı oluşturun", + "Repeat Password": "Şifrenizi tekrar girin", + respTime: "Cevap Süresi (ms)", + notAvailableShort: "N/A", + Create: "Yarat", + "Clear Data": "Verileri Temizle", + Events: "Olaylar", + Heartbeats: "Sağlık Durumları", + "Auto Get": "Otomatik Al" +} diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 03fd89f5..0e809f73 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -232,6 +232,12 @@

Molim Vas koristite ovo sa pažnjom.

+ +