add reset password in cli
This commit is contained in:
		
							parent
							
								
									6f489e7e0f
								
							
						
					
					
						commit
						d0aad3400c
					
				
					 6 changed files with 115 additions and 20 deletions
				
			
		
							
								
								
									
										59
									
								
								extra/reset-password.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								extra/reset-password.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| console.log("== Uptime Kuma Reset Password Tool =="); | ||||
| 
 | ||||
| console.log("Loading the database"); | ||||
| 
 | ||||
| const Database = require("../server/database"); | ||||
| const { R } = require("redbean-node"); | ||||
| const readline = require("readline"); | ||||
| const { initJWTSecret } = require("../server/util-server"); | ||||
| const rl = readline.createInterface({ | ||||
|     input: process.stdin, | ||||
|     output: process.stdout | ||||
| }); | ||||
| 
 | ||||
| (async () => { | ||||
|     await Database.connect(); | ||||
| 
 | ||||
|     try { | ||||
|         const user = await R.findOne("user"); | ||||
| 
 | ||||
|         if (! user) { | ||||
|             throw new Error("user not found, have you installed?"); | ||||
|         } | ||||
| 
 | ||||
|         console.log("Found user: " + user.username); | ||||
| 
 | ||||
|         while (true) { | ||||
|             let password = await question("New Password: "); | ||||
|             let confirmPassword = await question("Confirm New Password: "); | ||||
| 
 | ||||
|             if (password === confirmPassword) { | ||||
|                 await user.resetPassword(password); | ||||
| 
 | ||||
|                 // Reset all sessions by reset jwt secret
 | ||||
|                 await initJWTSecret(); | ||||
| 
 | ||||
|                 rl.close(); | ||||
|                 break; | ||||
|             } else { | ||||
|                 console.log("Passwords do not match, please try again."); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         console.log("Password reset successfully."); | ||||
|     } catch (e) { | ||||
|         console.error("Error: " + e.message); | ||||
|     } | ||||
| 
 | ||||
|     await Database.close(); | ||||
| 
 | ||||
|     console.log("Finished. You should restart the Uptime Kuma server.") | ||||
| })(); | ||||
| 
 | ||||
| function question(question) { | ||||
|     return new Promise((resolve) => { | ||||
|         rl.question(question, (answer) => { | ||||
|             resolve(answer); | ||||
|         }) | ||||
|     }); | ||||
| } | ||||
|  | @ -21,7 +21,8 @@ | |||
|         "build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push", | ||||
|         "setup": "git checkout 1.0.10 && npm install && npm run build", | ||||
|         "update-version": "node extra/update-version.js", | ||||
|         "mark-as-nightly": "node extra/mark-as-nightly.js" | ||||
|         "mark-as-nightly": "node extra/mark-as-nightly.js", | ||||
|         "reset-password": "node extra/reset-password.js" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@fortawesome/fontawesome-svg-core": "^1.2.36", | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ class Database { | |||
|     static latestVersion = 6; | ||||
|     static noReject = true; | ||||
| 
 | ||||
|     static connect() { | ||||
|     static async connect() { | ||||
|         const Dialect = require("knex/lib/dialects/sqlite3/index.js"); | ||||
|         Dialect.prototype._driver = () => require("@louislam/sqlite3"); | ||||
| 
 | ||||
|  | @ -27,6 +27,10 @@ class Database { | |||
|                 idleTimeoutMillis: 30000, | ||||
|             } | ||||
|         })); | ||||
| 
 | ||||
|         // Auto map the model to a bean object
 | ||||
|         R.freeze(true) | ||||
|         await R.autoloadModels("./server/model"); | ||||
|     } | ||||
| 
 | ||||
|     static async patch() { | ||||
|  |  | |||
							
								
								
									
										21
									
								
								server/model/user.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								server/model/user.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| const { BeanModel } = require("redbean-node/dist/bean-model"); | ||||
| const passwordHash = require("../password-hash"); | ||||
| const { R } = require("redbean-node"); | ||||
| 
 | ||||
| class User extends BeanModel { | ||||
| 
 | ||||
|     /** | ||||
|      * Direct execute, no need R.store() | ||||
|      * @param newPassword | ||||
|      * @returns {Promise<void>} | ||||
|      */ | ||||
|     async resetPassword(newPassword) { | ||||
|         await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ | ||||
|             passwordHash.generate(newPassword), | ||||
|             this.id | ||||
|         ]); | ||||
|         this.password = newPassword; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| module.exports = User; | ||||
|  | @ -27,7 +27,7 @@ console.log("Importing this project modules"); | |||
| debug("Importing Monitor"); | ||||
| const Monitor = require("./model/monitor"); | ||||
| debug("Importing Settings"); | ||||
| const { getSettings, setSettings, setting } = require("./util-server"); | ||||
| const { getSettings, setSettings, setting, initJWTSecret } = require("./util-server"); | ||||
| debug("Importing Notification"); | ||||
| const { Notification } = require("./notification"); | ||||
| debug("Importing Database"); | ||||
|  | @ -414,10 +414,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); | |||
| 
 | ||||
|                 if (user && passwordHash.verify(password.currentPassword, user.password)) { | ||||
| 
 | ||||
|                     await R.exec("UPDATE `user` SET password = ? WHERE id = ? ", [ | ||||
|                         passwordHash.generate(password.newPassword), | ||||
|                         socket.userID, | ||||
|                     ]); | ||||
|                     user.resetPassword(password.newPassword); | ||||
| 
 | ||||
|                     callback({ | ||||
|                         ok: true, | ||||
|  | @ -659,30 +656,22 @@ async function initDatabase() { | |||
|     } | ||||
| 
 | ||||
|     console.log("Connecting to Database") | ||||
|     Database.connect(); | ||||
|     await Database.connect(); | ||||
|     console.log("Connected") | ||||
| 
 | ||||
|     // Patch the database
 | ||||
|     await Database.patch() | ||||
| 
 | ||||
|     // Auto map the model to a bean object
 | ||||
|     R.freeze(true) | ||||
|     await R.autoloadModels("./server/model"); | ||||
| 
 | ||||
|     let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [ | ||||
|         "jwtSecret", | ||||
|     ]); | ||||
| 
 | ||||
|     if (! jwtSecretBean) { | ||||
|         console.log("JWT secret is not found, generate one.") | ||||
|         jwtSecretBean = R.dispense("setting") | ||||
|         jwtSecretBean.key = "jwtSecret" | ||||
| 
 | ||||
|         jwtSecretBean.value = passwordHash.generate(dayjs() + "") | ||||
|         await R.store(jwtSecretBean) | ||||
|         console.log("Stored JWT secret into database") | ||||
|         console.log("JWT secret is not found, generate one."); | ||||
|         jwtSecretBean = initJWTSecret(); | ||||
|         console.log("Stored JWT secret into database"); | ||||
|     } else { | ||||
|         console.log("Load JWT secret from database.") | ||||
|         console.log("Load JWT secret from database."); | ||||
|     } | ||||
| 
 | ||||
|     // If there is no record in user table, it is a new Uptime Kuma instance, need to setup
 | ||||
|  |  | |||
|  | @ -2,6 +2,27 @@ const tcpp = require("tcp-ping"); | |||
| const Ping = require("./ping-lite"); | ||||
| const { R } = require("redbean-node"); | ||||
| const { debug } = require("../src/util"); | ||||
| const passwordHash = require("./password-hash"); | ||||
| const dayjs = require("dayjs"); | ||||
| 
 | ||||
| /** | ||||
|  * Init or reset JWT secret | ||||
|  * @returns {Promise<Bean>} | ||||
|  */ | ||||
| exports.initJWTSecret = async () => { | ||||
|     let jwtSecretBean = await R.findOne("setting", " `key` = ? ", [ | ||||
|         "jwtSecret", | ||||
|     ]); | ||||
| 
 | ||||
|     if (! jwtSecretBean) { | ||||
|         jwtSecretBean = R.dispense("setting"); | ||||
|         jwtSecretBean.key = "jwtSecret"; | ||||
|     } | ||||
| 
 | ||||
|     jwtSecretBean.value = passwordHash.generate(dayjs() + ""); | ||||
|     await R.store(jwtSecretBean); | ||||
|     return jwtSecretBean; | ||||
| } | ||||
| 
 | ||||
| exports.tcping = function (hostname, port) { | ||||
|     return new Promise((resolve, reject) => { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue