diff --git a/extra/remove-2fa.js b/extra/remove-2fa.js new file mode 100644 index 000000000..0f3f63462 --- /dev/null +++ b/extra/remove-2fa.js @@ -0,0 +1,60 @@ +console.log("== Uptime Kuma Remove 2FA Tool =="); +console.log("Loading the database"); + +const Database = require("../server/database"); +const { R } = require("redbean-node"); +const readline = require("readline"); +const TwoFA = require("../server/2fa"); +const args = require("args-parser")(process.argv); +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +const main = async () => { + Database.init(args); + await Database.connect(); + + try { + // No need to actually reset the password for testing, just make sure no connection problem. It is ok for now. + if (!process.env.TEST_BACKEND) { + const user = await R.findOne("user"); + if (! user) { + throw new Error("user not found, have you installed?"); + } + + console.log("Found user: " + user.username); + + let ans = await question("Are you sure want to remove 2FA? [y/N]"); + + if (ans.toLowerCase() === "y") { + await TwoFA.disable2FA(user.id); + console.log("2FA has been removed successfully."); + } + + } + } catch (e) { + console.error("Error: " + e.message); + } + + await Database.close(); + rl.close(); + + console.log("Finished."); +}; + +function question(question) { + return new Promise((resolve) => { + rl.question(question, (answer) => { + resolve(answer); + }); + }); +} + +if (!process.env.TEST_BACKEND) { + main(); +} + +module.exports = { + main, +}; diff --git a/package.json b/package.json index c7ec3d8ee..79f01b558 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "update-version": "node extra/update-version.js", "mark-as-nightly": "node extra/mark-as-nightly.js", "reset-password": "node extra/reset-password.js", + "remove-2fa": "node extra/remove-2fa.js", "compile-install-script": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./extra/compile-install-script.ps1", "test-install-script-centos7": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/centos7.dockerfile .", "test-install-script-alpine3": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/alpine3.dockerfile .", diff --git a/server/2fa.js b/server/2fa.js new file mode 100644 index 000000000..bc8145cff --- /dev/null +++ b/server/2fa.js @@ -0,0 +1,14 @@ +const { checkLogin } = require("./util-server"); +const { R } = require("redbean-node"); + +class TwoFA { + + static async disable2FA(userID) { + return await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [ + userID, + ]); + } + +} + +module.exports = TwoFA; diff --git a/server/server.js b/server/server.js index d1fd7ff29..78106515a 100644 --- a/server/server.js +++ b/server/server.js @@ -120,6 +120,7 @@ module.exports.io = io; const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo } = require("./client"); const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler"); const databaseSocketHandler = require("./socket-handlers/database-socket-handler"); +const TwoFA = require("./2fa"); app.use(express.json()); @@ -420,10 +421,7 @@ exports.entryPage = "dashboard"; socket.on("disable2FA", async (callback) => { try { checkLogin(socket); - - await R.exec("UPDATE `user` SET twofa_status = 0 WHERE id = ? ", [ - socket.userID, - ]); + await TwoFA.disable2FA(socket.userID); callback({ ok: true, diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js index 105755d62..63ac34a9e 100644 --- a/src/languages/it-IT.js +++ b/src/languages/it-IT.js @@ -175,7 +175,7 @@ export default { "Entry Page": "Pagina Principale", statusPageNothing: "Non c'è nulla qui, aggiungere un gruppo oppure un monitoraggio.", "No Services": "Nessun Servizio", - "All Systems Operational": "Tutti i sistemi sono operativi", + "All Systems Operational": "Tutti i sistemi sono funzionali", "Partially Degraded Service": "Servizio parzialmente degradato", "Degraded Service": "Servizio degradato", "Add Group": "Aggiungi Gruppo", @@ -304,7 +304,7 @@ export default { PasswordsDoNotMatch: "Le password non corrispondono.", records: "records", "One record": "One record", - steamApiKeyDescription: "Per monitorare un server di gioco Steam si necessita della chiave Steam Web-API. È possibile registrare la propria chiave API qui: ", + steamApiKeyDescription: "Per monitorare un server di gioco Steam si necessita della chiave Web-API di Steam. È possibile registrare la propria chiave API qui: ", "Current User": "Utente corrente", recent: "Recenti", }; diff --git a/src/languages/ja.js b/src/languages/ja.js index f96028e42..9446c78c9 100644 --- a/src/languages/ja.js +++ b/src/languages/ja.js @@ -17,7 +17,7 @@ export default { pauseMonitorMsg: "一時停止しますか?", Settings: "設定", Dashboard: "ダッシュボード", - "New Update": "New Update", + "New Update": "新しいアップデート", Language: "言語", Appearance: "外観", Theme: "テーマ", @@ -53,7 +53,7 @@ export default { Ping: "Ping", "Monitor Type": "監視タイプ", Keyword: "キーワード", - "Friendly Name": "Friendly Name", + "Friendly Name": "分かりやすい名前", URL: "URL", Hostname: "ホスト名", Port: "ポート", @@ -104,60 +104,60 @@ export default { "Resolver Server": "問い合わせ先DNSサーバ", "Resource Record Type": "DNSレコード設定", "Last Result": "最終結果", - "Create your admin account": "Create your admin account", - "Repeat Password": "Repeat Password", - respTime: "Resp. Time (ms)", + "Create your admin account": "Adminアカウントの作成", + "Repeat Password": "パスワード確認", + respTime: "応答時間 (ms)", notAvailableShort: "N/A", - Create: "Create", - clearEventsMsg: "Are you sure want to delete all events for this monitor?", - clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?", - confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?", - "Clear Data": "Clear Data", - Events: "Events", - Heartbeats: "Heartbeats", - "Auto Get": "Auto Get", - enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.", - "Default enabled": "Default enabled", - "Also apply to existing monitors": "Also apply to existing monitors", - Export: "Export", - Import: "Import", - backupDescription: "You can backup all monitors and all notifications into a JSON file.", - backupDescription2: "PS: History and event data is not included.", - backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.", - alertNoFile: "Please select a file to import.", - alertWrongFileType: "Please select a JSON file.", - 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", + Create: "作成", + clearEventsMsg: "この監視のすべての記録を削除してもよろしいですか?", + clearHeartbeatsMsg: "この監視のすべての異常記録を削除してもよろしいですか?", + confirmClearStatisticsMsg: "すべての統計を削除してもよろしいですか?", + "Clear Data": "データを削除", + Events: "統計", + Heartbeats: "異常記録", + "Auto Get": "自動取得", + enableDefaultNotificationDescription: "監視を作成するごとに、この通知方法はデフォルトで有効になります。監視ごとに通知を無効にすることもできます。", + "Default enabled": "デフォルトで有効にする", + "Also apply to existing monitors": "既存のモニターにも適用する", + Export: "エクスポート", + Import: "インポート", + backupDescription: "すべての監視と通知方法をJSONファイルにできます。", + backupDescription2: "※ 履歴と統計のデータはバックアップされません。", + backupDescription3: "通知に使用するトークンなどの機密データも含まれています。注意して扱ってください。", + alertNoFile: "インポートするファイルを選択してください。", + alertWrongFileType: "JSONファイルを選択してください。", + twoFAVerifyLabel: "トークンを入力して、2段階認証を有効にします。", + tokenValidSettingsMsg: "トークンの確認が完了しました! 「保存」をしてください。", + confirmEnableTwoFAMsg: "2段階認証を「有効」にします。よろしいですか?", + confirmDisableTwoFAMsg: "2段階認証を「無効」にします。よろしいですか?", + "Apply on all existing monitors": "既存のすべてのモニターに適用する", + "Verify Token": "認証する", + "Setup 2FA": "2段階認証の設定", + "Enable 2FA": "2段階認証を有効にする", + "Disable 2FA": "2段階認証を無効にする", + "2FA Settings": "2段階認証の設定", + "Two Factor Authentication": "2段階認証", Active: "Active", Inactive: "Inactive", Token: "Token", "Show URI": "Show URI", - "Clear all statistics": "Clear all Statistics", + "Clear all statistics": "すべての記録を削除", retryCheckEverySecond: "Retry every {0} seconds.", - importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.", - confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.", - "Heartbeat Retry Interval": "Heartbeat Retry Interval", - "Import Backup": "Import Backup", - "Export Backup": "Export Backup", - "Skip existing": "Skip existing", - Overwrite: "Overwrite", - Options: "Options", - "Keep both": "Keep both", - Tags: "Tags", - "Add New below or Select...": "Add New below or Select...", - "Tag with this name already exist.": "Tag with this name already exist.", - "Tag with this value already exist.": "Tag with this value already exist.", - color: "color", - "value (optional)": "value (optional)", + importHandleDescription: "同じ名前のすべての監視または通知方法を上書きしない場合は、「既存のをスキップ」を選択します。 「上書きする」は、既存のすべてのモニターと通知を削除します。", + confirmImportMsg: "バックアップをインポートしてもよろしいですか?希望するオプションを選択してください。", + "Heartbeat Retry Interval": "異常検知後の再試行間隔", + "Import Backup": "バックアップのインポート", + "Export Backup": "バックアップのエクスポート", + "Skip existing": "既存のをスキップする", + Overwrite: "上書きする", + Options: "オプション", + "Keep both": "どちらも保持する", + Tags: "タグ", + "Add New below or Select...": "新規追加または選択...", + "Tag with this name already exist.": "この名前のタグはすでに存在しています。", + "Tag with this value already exist.": "この値のタグはすでに存在しています。", + color: "色", + "value (optional)": "値 (optional)", Gray: "Gray", Red: "Red", Orange: "Orange", @@ -166,20 +166,20 @@ export default { Indigo: "Indigo", Purple: "Purple", Pink: "Pink", - "Search...": "Search...", - "Avg. Ping": "Avg. Ping", - "Avg. Response": "Avg. Response", - "Entry Page": "Entry Page", - statusPageNothing: "Nothing here, please add a group or a monitor.", + "Search...": "検索...", + "Avg. Ping": "平均Ping時間", + "Avg. Response": "平均応答時間", + "Entry Page": "エントリーページ", + statusPageNothing: "ここには何もありません。グループまたは監視を追加してください。", "No Services": "No Services", - "All Systems Operational": "All Systems Operational", - "Partially Degraded Service": "Partially Degraded Service", - "Degraded Service": "Degraded Service", - "Add Group": "Add Group", - "Add a monitor": "Add a monitor", - "Edit Status Page": "Edit Status Page", - "Go to Dashboard": "Go to Dashboard", - "Status Page": "Status Page", + "All Systems Operational": "すべてのサービスが稼働中", + "Partially Degraded Service": "部分的にサービスが停止中", + "Degraded Service": "サービスが停止中", + "Add Group": "グループの追加", + "Add a monitor": "監視の追加", + "Edit Status Page": "ステータスページ編集", + "Go to Dashboard": "ダッシュボード", + "Status Page": "ステータスページ", telegram: "Telegram", webhook: "Webhook", smtp: "Email (SMTP)", diff --git a/src/languages/vi.js b/src/languages/vi.js index 0bfa3f208..bc2e86de0 100644 --- a/src/languages/vi.js +++ b/src/languages/vi.js @@ -33,21 +33,22 @@ export default { Appearance: "Giao diện", Theme: "Theme", General: "Chung", + "Primary Base URL": "URL chính", Version: "Phiên bản", "Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub", List: "List", Add: "Thêm", "Add New Monitor": "Thêm mới Monitor", "Quick Stats": "Thống kê nhanh", - Up: "Lên", - Down: "Xuống", + Up: "Up", + Down: "Down", Pending: "Chờ xử lý", Unknown: "Không xác định", Pause: "Tạm dừng", Name: "Tên", Status: "Trạng thái", DateTime: "Ngày tháng", - Message: "Tin nhắn", + Message: "Trạng thái request", "No important events": "Không có sự kiện quan trọng nào", Resume: "Khôi phục", Edit: "Sửa", @@ -64,17 +65,20 @@ export default { Ping: "Ping", "Monitor Type": "Kiểu monitor", Keyword: "Từ khoá", - "Friendly Name": "Tên dễ hiểu", + "Friendly Name": "Tên monitor", URL: "URL", Hostname: "Hostname", Port: "Port", - "Heartbeat Interval": "Tần suất heartbeat", + "Heartbeat Interval": "Tần suất kiểm tra", Retries: "Thử lại", - "Heartbeat Retry Interval": "Tần suất thử lại của Heartbeat", + "Heartbeat Retry Interval": "Tần suất kiểm tra lại", Advanced: "Nâng cao", - "Upside Down Mode": "Trạng thái đảo ngược", - "Max. Redirects": "Chuyển hướng tối đa", + "Upside Down Mode": "Chế độ đảo ngược", + "Max. Redirects": "Số chuyển hướng tối đa", "Accepted Status Codes": "Codes trạng thái chấp nhận", + "Push URL": "Push URL", + needPushEvery: "Bạn nên gọi URL mỗi {0} giây.", + pushOptionalParams: "Tuỳ chỉnh parameters: {0}", Save: "Lưu", Notifications: "Thông báo", "Not available, please setup.": "Chưa sẵn sàng, hãy cài đặt.", @@ -131,7 +135,7 @@ export default { Events: "Sự kiện", Heartbeats: "Heartbeats", "Auto Get": "Tự động lấy", - backupDescription: "Bạn có thể sao lưu tất cả các màn hình và tất cả các thông báo vào một file JSON.", + backupDescription: "Bạn có thể sao lưu tất cả các monitor và tất cả các thông báo vào một file JSON.", backupDescription2: "PS: Không bao gồm dữ liệu lịch sử các sự kiện.", backupDescription3: "Hãy lưu giữ file này cẩn thận vì trong file đó chứa cả các mã token thông báo.", alertNoFile: "Hãy chọn file để khôi phục.", @@ -171,7 +175,7 @@ export default { "Entry Page": "Entry Page", statusPageNothing: "Không có gì, hãy thêm nhóm monitor hoặc monitor.", "No Services": "Không có dịch vụ", - "All Systems Operational": "Tất cả các hệ thống hoạt động", + "All Systems Operational": "Tất cả các hệ thống hoạt động bình thường", "Partially Degraded Service": "Dịch vụ xuống cấp một phần", "Degraded Service": "Degraded Service", "Add Group": "Thêm nhóm", @@ -184,7 +188,7 @@ export default { Required: "Bắt buộc", telegram: "Telegram", "Bot Token": "Bot Token", - "You can get a token from": "Bạn có thể lấy mã token từ", + wayToGetTelegramToken: "Bạn có thể lấy mã token từ", "Chat ID": "Chat ID", supportTelegramChatID: "Hỗ trợ chat trực tiếp / Nhóm / Kênh Chat ID", wayToGetTelegramChatID: "Bạn có thể lấy chat id của mình bằng cách gửi tin nhắn tới bot và truy cập url này để xem chat_id:", @@ -200,6 +204,7 @@ export default { secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Bỏ qua lỗi TLS", "From Email": "Từ Email", + emailCustomSubject: "Tuỳ chỉnh tiêu đề", "To Email": "Tới Email", smtpCC: "CC", smtpBCC: "BCC", @@ -212,7 +217,7 @@ export default { teams: "Microsoft Teams", "Webhook URL": "Webhook URL", wayToGetTeamsURL: "Bạn có thể học cách tạo webhook url {0}.", - signal: "Signal", + signal: "Tín hiệu", Number: "Số", Recipients: "Người nhận", needSignalAPI: "Bạn cần một tín hiệu client với REST API.", @@ -235,8 +240,9 @@ export default { pushy: "Pushy", octopush: "Octopush", promosms: "PromoSMS", + clicksendsms: "ClickSend SMS", lunasea: "LunaSea", - apprise: "Thông báo (Hỗ trợ 50+ dịch vụ thông báo)", + apprise: "Apprise (Hỗ trợ 50+ dịch vụ thông báo)", pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", @@ -250,8 +256,11 @@ export default { "SMS Type": "SMS Type", octopushTypePremium: "Premium (Nhanh - Khuyến nghị nên dùng cho cảnh báo)", octopushTypeLowCost: "Giá rẻ (Chậm, thỉnh thoảng bị chặn)", + checkPrice: "Kiểm tra giá {0}:", + apiCredentials: "API credentials", + octopushLegacyHint: "Bạn muốn sử dụng phiên bản cũ của Octopush (2011-2020) hay phiên bản mới?", "Check octopush prices": "Kiểm tra giá octopush {0}.", - octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +33612345678) ", + octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +84123456789) ", octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)", "LunaSea Device ID": "LunaSea ID thiết bị", "Apprise URL": "Apprise URL", @@ -280,4 +289,22 @@ export default { promosmsPhoneNumber: "Số điện thoại (Bỏ qua mã vùng với người Ba Lan)", promosmsSMSSender: "SMS Tên người gửi: Tên đã đăng ký trước hoặc tên mặc định: InfoSMS, SMS Info, MaxSMS, INFO, SMS", "Feishu WebHookUrl": "Feishu WebHookUrl", + matrixHomeserverURL: "Homeserver URL (với http(s):// và port tuỳ chỉnh)", + "Internal Room Id": "Room ID Nội bộ", + matrixDesc1: "Bạn có thể tìm thấy room ID nội bộ bằng cách tìm trong mục advanced của phần room settings trong Matrix client của bạn. Nó có dạng giống như !QMdRCpUIfLwsfjxye6:home.server.", + matrixDesc2: "Bạn nên tạo người dùng mới và đừng sử dụng mã token truy cập của Matrix user vì nó sẽ cho phép truy cập toàn quyền vào tài khoản của bạn và tất cả các phòng bạn đã tham gia. Thay vào đó, hãy tạo một người dùng mới và chỉ mời người đó vào phòng mà bạn muốn nhận thông báo. Bạn có thể lấy được mã token truy cập bằng cách chạy {0}", + Method: "Method", + Body: "Body", + Headers: "Headers", + PushUrl: "Push URL", + HeadersInvalidFormat: "Header request không hợp lệ JSON: ", + BodyInvalidFormat: "Tequest body không hợp lệ JSON: ", + "Monitor History": "Lịch sử Monitor", + clearDataOlderThan: "Giữ dữ liệu lịch sử monitor {0} ngày.", + PasswordsDoNotMatch: "Passwords không khớp.", + records: "records", + "One record": "One record", + steamApiKeyDescription: "Để monitor các Steam Game Server bạn cần một Steam Web-API key. Bạn có thể đăng ký API key tại đây: ", + "Current User": "User hiện tại", + recent: "Gần đây", };