diff --git a/server/Database.js b/server/Database.js index 65c8d539c..50ff714ef 100644 --- a/server/Database.js +++ b/server/Database.js @@ -420,9 +420,21 @@ class Database { */ async createRootUser(username, pash, auth) { if (!this.sequelize) return false - await this.userModel.createRootUser(username, pash, auth) - this.hasRootUser = true - return true + const transaction = await this.sequelize.transaction() + try { + const rootCount = await this.userModel.count({ where: { type: 'root' }, transaction }) + if (rootCount > 0) { + await transaction.rollback() + return false + } + await this.userModel.createRootUser(username, pash, auth, transaction) + await transaction.commit() + this.hasRootUser = true + return true + } catch (error) { + await transaction.rollback() + throw error + } } updateServerSettings() { diff --git a/server/Server.js b/server/Server.js index 5fac001d8..65ecf8de8 100644 --- a/server/Server.js +++ b/server/Server.js @@ -472,7 +472,11 @@ class Server { const rootUsername = newRoot.username || 'root' const rootPash = newRoot.password ? await this.auth.localAuthStrategy.hashPassword(newRoot.password) : '' if (!rootPash) Logger.warn(`[Server] Creating root user with no password`) - await Database.createRootUser(rootUsername, rootPash, this.auth) + const created = await Database.createRootUser(rootUsername, rootPash, this.auth) + if (!created) { + Logger.error(`[Server] attempt to init server when server already has a root user`) + return res.sendStatus(500) + } res.sendStatus(200) } diff --git a/server/models/User.js b/server/models/User.js index 0b9d49438..9ad4772d5 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -189,7 +189,7 @@ class User extends Model { * @param {import('../Auth')} auth * @returns {Promise} */ - static async createRootUser(username, pash, auth) { + static async createRootUser(username, pash, auth, transaction = null) { const userId = uuidv4() const token = auth.generateAccessToken({ id: userId, username }) @@ -207,7 +207,7 @@ class User extends Model { seriesHideFromContinueListening: [] } } - return this.create(newUser) + return this.create(newUser, { transaction }) } /**