mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-11-01 03:49:24 +08:00 
			
		
		
		
	Some improvements
This commit is contained in:
		| @@ -12,6 +12,10 @@ const { loginRateLimiter } = require("./rate-limiter"); | |||||||
|  * @returns {Promise<Bean|null>} |  * @returns {Promise<Bean|null>} | ||||||
|  */ |  */ | ||||||
| exports.login = async function (username, password) { | exports.login = async function (username, password) { | ||||||
|  |     if (typeof username !== "string" || typeof password !== "string") { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     let user = await R.findOne("user", " username = ? AND active = 1 ", [ |     let user = await R.findOne("user", " username = ? AND active = 1 ", [ | ||||||
|         username, |         username, | ||||||
|     ]); |     ]); | ||||||
|   | |||||||
| @@ -34,6 +34,14 @@ const loginRateLimiter = new KumaRateLimiter({ | |||||||
|     errorMessage: "Too frequently, try again later." |     errorMessage: "Too frequently, try again later." | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | const twoFaRateLimiter = new KumaRateLimiter({ | ||||||
|  |     tokensPerInterval: 30, | ||||||
|  |     interval: "minute", | ||||||
|  |     fireImmediately: true, | ||||||
|  |     errorMessage: "Too frequently, try again later." | ||||||
|  | }); | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     loginRateLimiter |     loginRateLimiter, | ||||||
|  |     twoFaRateLimiter, | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										120
									
								
								server/server.js
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								server/server.js
									
									
									
									
									
								
							| @@ -52,7 +52,7 @@ console.log("Importing this project modules"); | |||||||
| debug("Importing Monitor"); | debug("Importing Monitor"); | ||||||
| const Monitor = require("./model/monitor"); | const Monitor = require("./model/monitor"); | ||||||
| debug("Importing Settings"); | debug("Importing Settings"); | ||||||
| const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog } = require("./util-server"); | const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog, doubleCheckPassword } = require("./util-server"); | ||||||
|  |  | ||||||
| debug("Importing Notification"); | debug("Importing Notification"); | ||||||
| const { Notification } = require("./notification"); | const { Notification } = require("./notification"); | ||||||
| @@ -63,7 +63,7 @@ const Database = require("./database"); | |||||||
|  |  | ||||||
| debug("Importing Background Jobs"); | debug("Importing Background Jobs"); | ||||||
| const { initBackgroundJobs } = require("./jobs"); | const { initBackgroundJobs } = require("./jobs"); | ||||||
| const { loginRateLimiter } = require("./rate-limiter"); | const { loginRateLimiter, twoFaRateLimiter } = require("./rate-limiter"); | ||||||
|  |  | ||||||
| const { basicAuth } = require("./auth"); | const { basicAuth } = require("./auth"); | ||||||
| const { login } = require("./auth"); | const { login } = require("./auth"); | ||||||
| @@ -305,6 +305,15 @@ exports.entryPage = "dashboard"; | |||||||
|         socket.on("login", async (data, callback) => { |         socket.on("login", async (data, callback) => { | ||||||
|             console.log("Login"); |             console.log("Login"); | ||||||
|  |  | ||||||
|  |             // Checking | ||||||
|  |             if (typeof callback !== "function") { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!data) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // Login Rate Limit |             // Login Rate Limit | ||||||
|             if (! await loginRateLimiter.pass(callback)) { |             if (! await loginRateLimiter.pass(callback)) { | ||||||
|                 return; |                 return; | ||||||
| @@ -363,14 +372,27 @@ exports.entryPage = "dashboard"; | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("logout", async (callback) => { |         socket.on("logout", async (callback) => { | ||||||
|  |             // Rate Limit | ||||||
|  |             if (! await loginRateLimiter.pass(callback)) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             socket.leave(socket.userID); |             socket.leave(socket.userID); | ||||||
|             socket.userID = null; |             socket.userID = null; | ||||||
|             callback(); |  | ||||||
|  |             if (typeof callback === "function") { | ||||||
|  |                 callback(); | ||||||
|  |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("prepare2FA", async (callback) => { |         socket.on("prepare2FA", async (currentPassword, callback) => { | ||||||
|             try { |             try { | ||||||
|  |                 if (! await twoFaRateLimiter.pass(callback)) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |                 await doubleCheckPassword(socket, currentPassword); | ||||||
|  |  | ||||||
|                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ |                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ | ||||||
|                     socket.userID, |                     socket.userID, | ||||||
| @@ -405,14 +427,19 @@ exports.entryPage = "dashboard"; | |||||||
|             } catch (error) { |             } catch (error) { | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to prepare 2FA.", |                     msg: error.message, | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("save2FA", async (callback) => { |         socket.on("save2FA", async (currentPassword, callback) => { | ||||||
|             try { |             try { | ||||||
|  |                 if (! await twoFaRateLimiter.pass(callback)) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |                 await doubleCheckPassword(socket, currentPassword); | ||||||
|  |  | ||||||
|                 await R.exec("UPDATE `user` SET twofa_status = 1 WHERE id = ? ", [ |                 await R.exec("UPDATE `user` SET twofa_status = 1 WHERE id = ? ", [ | ||||||
|                     socket.userID, |                     socket.userID, | ||||||
| @@ -425,14 +452,19 @@ exports.entryPage = "dashboard"; | |||||||
|             } catch (error) { |             } catch (error) { | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to change 2FA.", |                     msg: error.message, | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("disable2FA", async (callback) => { |         socket.on("disable2FA", async (currentPassword, callback) => { | ||||||
|             try { |             try { | ||||||
|  |                 if (! await twoFaRateLimiter.pass(callback)) { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |                 await doubleCheckPassword(socket, currentPassword); | ||||||
|                 await TwoFA.disable2FA(socket.userID); |                 await TwoFA.disable2FA(socket.userID); | ||||||
|  |  | ||||||
|                 callback({ |                 callback({ | ||||||
| @@ -442,36 +474,47 @@ exports.entryPage = "dashboard"; | |||||||
|             } catch (error) { |             } catch (error) { | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to change 2FA.", |                     msg: error.message, | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("verifyToken", async (token, callback) => { |         socket.on("verifyToken", async (token, currentPassword, callback) => { | ||||||
|             let user = await R.findOne("user", " id = ? AND active = 1 ", [ |             try { | ||||||
|                 socket.userID, |                 checkLogin(socket); | ||||||
|             ]); |                 await doubleCheckPassword(socket, currentPassword); | ||||||
|  |  | ||||||
|             let verify = notp.totp.verify(token, user.twofa_secret, twofa_verification_opts); |                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ | ||||||
|  |                     socket.userID, | ||||||
|  |                 ]); | ||||||
|  |  | ||||||
|             if (user.twofa_last_token !== token && verify) { |                 let verify = notp.totp.verify(token, user.twofa_secret, twofa_verification_opts); | ||||||
|                 callback({ |  | ||||||
|                     ok: true, |                 if (user.twofa_last_token !== token && verify) { | ||||||
|                     valid: true, |                     callback({ | ||||||
|                 }); |                         ok: true, | ||||||
|             } else { |                         valid: true, | ||||||
|  |                     }); | ||||||
|  |                 } else { | ||||||
|  |                     callback({ | ||||||
|  |                         ok: false, | ||||||
|  |                         msg: "Invalid Token.", | ||||||
|  |                         valid: false, | ||||||
|  |                     }); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             } catch (error) { | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Invalid Token.", |                     msg: error.message, | ||||||
|                     valid: false, |  | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("twoFAStatus", async (callback) => { |         socket.on("twoFAStatus", async (callback) => { | ||||||
|             checkLogin(socket); |  | ||||||
|  |  | ||||||
|             try { |             try { | ||||||
|  |                 checkLogin(socket); | ||||||
|  |  | ||||||
|                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ |                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ | ||||||
|                     socket.userID, |                     socket.userID, | ||||||
|                 ]); |                 ]); | ||||||
| @@ -488,9 +531,10 @@ exports.entryPage = "dashboard"; | |||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|  |                 console.log(error); | ||||||
|                 callback({ |                 callback({ | ||||||
|                     ok: false, |                     ok: false, | ||||||
|                     msg: "Error while trying to get 2FA status.", |                     msg: error.message, | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -936,21 +980,13 @@ exports.entryPage = "dashboard"; | |||||||
|                     throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length."); |                     throw new Error("Password is too weak. It should contain alphabetic and numeric characters. It must be at least 6 characters in length."); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 let user = await R.findOne("user", " id = ? AND active = 1 ", [ |                 let user = await doubleCheckPassword(socket, password.currentPassword); | ||||||
|                     socket.userID, |                 await user.resetPassword(password.newPassword); | ||||||
|                 ]); |  | ||||||
|  |  | ||||||
|                 if (user && passwordHash.verify(password.currentPassword, user.password)) { |                 callback({ | ||||||
|  |                     ok: true, | ||||||
|                     user.resetPassword(password.newPassword); |                     msg: "Password has been updated successfully.", | ||||||
|  |                 }); | ||||||
|                     callback({ |  | ||||||
|                         ok: true, |  | ||||||
|                         msg: "Password has been updated successfully.", |  | ||||||
|                     }); |  | ||||||
|                 } else { |  | ||||||
|                     throw new Error("Incorrect current password"); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 callback({ |                 callback({ | ||||||
| @@ -977,10 +1013,14 @@ exports.entryPage = "dashboard"; | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         socket.on("setSettings", async (data, callback) => { |         socket.on("setSettings", async (data, currentPassword, callback) => { | ||||||
|             try { |             try { | ||||||
|                 checkLogin(socket); |                 checkLogin(socket); | ||||||
|  |  | ||||||
|  |                 if (data.disableAuth) { | ||||||
|  |                     await doubleCheckPassword(socket, currentPassword); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 await setSettings("general", data); |                 await setSettings("general", data); | ||||||
|                 exports.entryPage = data.entryPage; |                 exports.entryPage = data.entryPage; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| const tcpp = require("tcp-ping"); | const tcpp = require("tcp-ping"); | ||||||
| const Ping = require("./ping-lite"); | const Ping = require("./ping-lite"); | ||||||
| const { R } = require("redbean-node"); | const { R } = require("redbean-node"); | ||||||
| const { debug } = require("../src/util"); | const { debug, genSecret } = require("../src/util"); | ||||||
| const passwordHash = require("./password-hash"); | const passwordHash = require("./password-hash"); | ||||||
| const dayjs = require("dayjs"); |  | ||||||
| const { Resolver } = require("dns"); | const { Resolver } = require("dns"); | ||||||
| const child_process = require("child_process"); | const child_process = require("child_process"); | ||||||
| const iconv = require("iconv-lite"); | const iconv = require("iconv-lite"); | ||||||
| @@ -32,7 +31,7 @@ exports.initJWTSecret = async () => { | |||||||
|         jwtSecretBean.key = "jwtSecret"; |         jwtSecretBean.key = "jwtSecret"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     jwtSecretBean.value = passwordHash.generate(dayjs() + ""); |     jwtSecretBean.value = passwordHash.generate(genSecret()); | ||||||
|     await R.store(jwtSecretBean); |     await R.store(jwtSecretBean); | ||||||
|     return jwtSecretBean; |     return jwtSecretBean; | ||||||
| }; | }; | ||||||
| @@ -321,6 +320,28 @@ exports.checkLogin = (socket) => { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * For logged-in users, double-check the password | ||||||
|  |  * @param socket | ||||||
|  |  * @param currentPassword | ||||||
|  |  * @returns {Promise<Bean>} | ||||||
|  |  */ | ||||||
|  | exports.doubleCheckPassword = async (socket, currentPassword) => { | ||||||
|  |     if (typeof currentPassword !== "string") { | ||||||
|  |         throw new Error("Wrong data type?"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let user = await R.findOne("user", " id = ? AND active = 1 ", [ | ||||||
|  |         socket.userID, | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|  |     if (!user || !passwordHash.verify(currentPassword, user.password)) { | ||||||
|  |         throw new Error("Incorrect current password"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return user; | ||||||
|  | }; | ||||||
|  |  | ||||||
| exports.startUnitTest = async () => { | exports.startUnitTest = async () => { | ||||||
|     console.log("Starting unit test..."); |     console.log("Starting unit test..."); | ||||||
|     const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm"; |     const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm"; | ||||||
|   | |||||||
| @@ -9,7 +9,9 @@ | |||||||
|                 <a v-if="searchText != ''" class="search-icon" @click="clearSearchText"> |                 <a v-if="searchText != ''" class="search-icon" @click="clearSearchText"> | ||||||
|                     <font-awesome-icon icon="times" /> |                     <font-awesome-icon icon="times" /> | ||||||
|                 </a> |                 </a> | ||||||
|                 <input v-model="searchText" class="form-control search-input" :placeholder="$t('Search...')" /> |                 <form> | ||||||
|  |                     <input v-model="searchText" class="form-control search-input" :placeholder="$t('Search...')" autocomplete="off" /> | ||||||
|  |                 </form> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="monitor-list" :class="{ scrollbar: scrollbar }"> |         <div class="monitor-list" :class="{ scrollbar: scrollbar }"> | ||||||
|   | |||||||
| @@ -19,6 +19,19 @@ | |||||||
|                             </div> |                             </div> | ||||||
|                             <p v-if="showURI && twoFAStatus == false" class="text-break mt-2">{{ uri }}</p> |                             <p v-if="showURI && twoFAStatus == false" class="text-break mt-2">{{ uri }}</p> | ||||||
|  |  | ||||||
|  |                             <div v-if="!(uri && twoFAStatus == false)" class="mb-3"> | ||||||
|  |                                 <label for="current-password" class="form-label"> | ||||||
|  |                                     {{ $t("Current Password") }} | ||||||
|  |                                 </label> | ||||||
|  |                                 <input | ||||||
|  |                                     id="current-password" | ||||||
|  |                                     v-model="currentPassword" | ||||||
|  |                                     type="password" | ||||||
|  |                                     class="form-control" | ||||||
|  |                                     required | ||||||
|  |                                 /> | ||||||
|  |                             </div> | ||||||
|  |  | ||||||
|                             <button v-if="uri == null && twoFAStatus == false" class="btn btn-primary" type="button" @click="prepare2FA()"> |                             <button v-if="uri == null && twoFAStatus == false" class="btn btn-primary" type="button" @click="prepare2FA()"> | ||||||
|                                 {{ $t("Enable 2FA") }} |                                 {{ $t("Enable 2FA") }} | ||||||
|                             </button> |                             </button> | ||||||
| @@ -59,11 +72,11 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { Modal } from "bootstrap" | import { Modal } from "bootstrap"; | ||||||
| import Confirm from "./Confirm.vue"; | import Confirm from "./Confirm.vue"; | ||||||
| import VueQrcode from "vue-qrcode" | import VueQrcode from "vue-qrcode"; | ||||||
| import { useToast } from "vue-toastification" | import { useToast } from "vue-toastification"; | ||||||
| const toast = useToast() | const toast = useToast(); | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     components: { |     components: { | ||||||
| @@ -73,35 +86,36 @@ export default { | |||||||
|     props: {}, |     props: {}, | ||||||
|     data() { |     data() { | ||||||
|         return { |         return { | ||||||
|  |             currentPassword: "", | ||||||
|             processing: false, |             processing: false, | ||||||
|             uri: null, |             uri: null, | ||||||
|             tokenValid: false, |             tokenValid: false, | ||||||
|             twoFAStatus: null, |             twoFAStatus: null, | ||||||
|             token: null, |             token: null, | ||||||
|             showURI: false, |             showURI: false, | ||||||
|         } |         }; | ||||||
|     }, |     }, | ||||||
|     mounted() { |     mounted() { | ||||||
|         this.modal = new Modal(this.$refs.modal) |         this.modal = new Modal(this.$refs.modal); | ||||||
|         this.getStatus(); |         this.getStatus(); | ||||||
|     }, |     }, | ||||||
|     methods: { |     methods: { | ||||||
|         show() { |         show() { | ||||||
|             this.modal.show() |             this.modal.show(); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         confirmEnableTwoFA() { |         confirmEnableTwoFA() { | ||||||
|             this.$refs.confirmEnableTwoFA.show() |             this.$refs.confirmEnableTwoFA.show(); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         confirmDisableTwoFA() { |         confirmDisableTwoFA() { | ||||||
|             this.$refs.confirmDisableTwoFA.show() |             this.$refs.confirmDisableTwoFA.show(); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         prepare2FA() { |         prepare2FA() { | ||||||
|             this.processing = true; |             this.processing = true; | ||||||
|  |  | ||||||
|             this.$root.getSocket().emit("prepare2FA", (res) => { |             this.$root.getSocket().emit("prepare2FA", this.currentPassword, (res) => { | ||||||
|                 this.processing = false; |                 this.processing = false; | ||||||
|  |  | ||||||
|                 if (res.ok) { |                 if (res.ok) { | ||||||
| @@ -109,49 +123,51 @@ export default { | |||||||
|                 } else { |                 } else { | ||||||
|                     toast.error(res.msg); |                     toast.error(res.msg); | ||||||
|                 } |                 } | ||||||
|             }) |             }); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         save2FA() { |         save2FA() { | ||||||
|             this.processing = true; |             this.processing = true; | ||||||
|  |  | ||||||
|             this.$root.getSocket().emit("save2FA", (res) => { |             this.$root.getSocket().emit("save2FA", this.currentPassword, (res) => { | ||||||
|                 this.processing = false; |                 this.processing = false; | ||||||
|  |  | ||||||
|                 if (res.ok) { |                 if (res.ok) { | ||||||
|                     this.$root.toastRes(res) |                     this.$root.toastRes(res); | ||||||
|                     this.getStatus(); |                     this.getStatus(); | ||||||
|  |                     this.currentPassword = ""; | ||||||
|                     this.modal.hide(); |                     this.modal.hide(); | ||||||
|                 } else { |                 } else { | ||||||
|                     toast.error(res.msg); |                     toast.error(res.msg); | ||||||
|                 } |                 } | ||||||
|             }) |             }); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         disable2FA() { |         disable2FA() { | ||||||
|             this.processing = true; |             this.processing = true; | ||||||
|  |  | ||||||
|             this.$root.getSocket().emit("disable2FA", (res) => { |             this.$root.getSocket().emit("disable2FA", this.currentPassword, (res) => { | ||||||
|                 this.processing = false; |                 this.processing = false; | ||||||
|  |  | ||||||
|                 if (res.ok) { |                 if (res.ok) { | ||||||
|                     this.$root.toastRes(res) |                     this.$root.toastRes(res); | ||||||
|                     this.getStatus(); |                     this.getStatus(); | ||||||
|  |                     this.currentPassword = ""; | ||||||
|                     this.modal.hide(); |                     this.modal.hide(); | ||||||
|                 } else { |                 } else { | ||||||
|                     toast.error(res.msg); |                     toast.error(res.msg); | ||||||
|                 } |                 } | ||||||
|             }) |             }); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         verifyToken() { |         verifyToken() { | ||||||
|             this.$root.getSocket().emit("verifyToken", this.token, (res) => { |             this.$root.getSocket().emit("verifyToken", this.token, this.currentPassword, (res) => { | ||||||
|                 if (res.ok) { |                 if (res.ok) { | ||||||
|                     this.tokenValid = res.valid; |                     this.tokenValid = res.valid; | ||||||
|                 } else { |                 } else { | ||||||
|                     toast.error(res.msg); |                     toast.error(res.msg); | ||||||
|                 } |                 } | ||||||
|             }) |             }); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         getStatus() { |         getStatus() { | ||||||
| @@ -161,10 +177,10 @@ export default { | |||||||
|                 } else { |                 } else { | ||||||
|                     toast.error(res.msg); |                     toast.error(res.msg); | ||||||
|                 } |                 } | ||||||
|             }) |             }); | ||||||
|         }, |         }, | ||||||
|     }, |     }, | ||||||
| } | }; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
| @@ -215,14 +215,14 @@ | |||||||
|                 <p>Dette er for <strong>de som har tredjepartsautorisering</strong> foran Uptime Kuma, for eksempel Cloudflare Access.</p> |                 <p>Dette er for <strong>de som har tredjepartsautorisering</strong> foran Uptime Kuma, for eksempel Cloudflare Access.</p> | ||||||
|                 <p>Vennligst vær forsiktig.</p> |                 <p>Vennligst vær forsiktig.</p> | ||||||
|             </template> |             </template> | ||||||
|              |  | ||||||
|             <template v-else-if="$i18n.locale === 'cs-CZ' "> |             <template v-else-if="$i18n.locale === 'cs-CZ' "> | ||||||
|                 <p>Opravdu chcete <strong>deaktivovat autentifikaci</strong>?</p> |                 <p>Opravdu chcete <strong>deaktivovat autentifikaci</strong>?</p> | ||||||
|                 <p>Tato možnost je určena pro případy, kdy <strong>máte autentifikaci zajištěnou třetí stranou</strong> ještě před přístupem do Uptime Kuma, například prostřednictvím Cloudflare Access.</p> |                 <p>Tato možnost je určena pro případy, kdy <strong>máte autentifikaci zajištěnou třetí stranou</strong> ještě před přístupem do Uptime Kuma, například prostřednictvím Cloudflare Access.</p> | ||||||
|                 <p>Používejte ji prosím s rozmyslem.</p> |                 <p>Používejte ji prosím s rozmyslem.</p> | ||||||
|             </template> |             </template> | ||||||
|  |  | ||||||
| 			<template v-else-if="$i18n.locale === 'vi-VN' "> |             <template v-else-if="$i18n.locale === 'vi-VN' "> | ||||||
|                 <p>Bạn có muốn <strong>TẮT XÁC THỰC</strong> không?</p> |                 <p>Bạn có muốn <strong>TẮT XÁC THỰC</strong> không?</p> | ||||||
|                 <p>Điều này rất nguy hiểm<strong>BẤT KỲ AI</strong> cũng có thể truy cập và cướp quyền điều khiển.</p> |                 <p>Điều này rất nguy hiểm<strong>BẤT KỲ AI</strong> cũng có thể truy cập và cướp quyền điều khiển.</p> | ||||||
|                 <p>Vui lòng <strong>cẩn thận</strong>.</p> |                 <p>Vui lòng <strong>cẩn thận</strong>.</p> | ||||||
| @@ -234,6 +234,19 @@ | |||||||
|                 <p>It is designed for scenarios <strong>where you intend to implement third-party authentication</strong> in front of Uptime Kuma such as Cloudflare Access, Authelia or other authentication mechanisms.</p> |                 <p>It is designed for scenarios <strong>where you intend to implement third-party authentication</strong> in front of Uptime Kuma such as Cloudflare Access, Authelia or other authentication mechanisms.</p> | ||||||
|                 <p>Please use this option carefully!</p> |                 <p>Please use this option carefully!</p> | ||||||
|             </template> |             </template> | ||||||
|  |  | ||||||
|  |             <div class="mb-3"> | ||||||
|  |                 <label for="current-password2" class="form-label"> | ||||||
|  |                     {{ $t("Current Password") }} | ||||||
|  |                 </label> | ||||||
|  |                 <input | ||||||
|  |                     id="current-password2" | ||||||
|  |                     v-model="password.currentPassword" | ||||||
|  |                     type="password" | ||||||
|  |                     class="form-control" | ||||||
|  |                     required | ||||||
|  |                 /> | ||||||
|  |             </div> | ||||||
|         </Confirm> |         </Confirm> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| @@ -310,7 +323,12 @@ export default { | |||||||
|  |  | ||||||
|         disableAuth() { |         disableAuth() { | ||||||
|             this.settings.disableAuth = true; |             this.settings.disableAuth = true; | ||||||
|             this.saveSettings(); |  | ||||||
|  |             // Need current password to disable auth | ||||||
|  |             // Set it to empty if done | ||||||
|  |             this.saveSettings(() => { | ||||||
|  |                 this.password.currentPassword = ""; | ||||||
|  |             }, this.password.currentPassword); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         enableAuth() { |         enableAuth() { | ||||||
|   | |||||||
| @@ -131,10 +131,18 @@ export default { | |||||||
|             }); |             }); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|         saveSettings() { |         /** | ||||||
|             this.$root.getSocket().emit("setSettings", this.settings, (res) => { |          * Save Settings | ||||||
|  |          * @param currentPassword (Optional) Only need for disableAuth to true | ||||||
|  |          */ | ||||||
|  |         saveSettings(callback, currentPassword) { | ||||||
|  |             this.$root.getSocket().emit("setSettings", this.settings, currentPassword, (res) => { | ||||||
|                 this.$root.toastRes(res); |                 this.$root.toastRes(res); | ||||||
|                 this.loadSettings(); |                 this.loadSettings(); | ||||||
|  |  | ||||||
|  |                 if (callback) { | ||||||
|  |                     callback(); | ||||||
|  |                 } | ||||||
|             }); |             }); | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user