module.exports = Self => { Self.getSynchronizer = async function() { return await Self.findOne({fields: ['id']}); }; Object.assign(Self.prototype, { async init() { const [row] = await Self.rawSql('SELECT VERSION() AS `version`'); if (row.version.includes('MariaDB')) this.dbType = 'MariaDB'; else this.dbType = 'MySQL'; }, async syncUser(userName, info, password) { const mysqlHost = '%'; let mysqlUser = userName; if (this.dbType == 'MySQL') mysqlUser = `!${mysqlUser}`; const [row] = await Self.rawSql( `SELECT COUNT(*) AS nRows FROM mysql.user WHERE User = ? AND Host = ?`, [mysqlUser, mysqlHost] ); let userExists = row.nRows > 0; let isUpdatable = true; if (this.dbType == 'MariaDB') { const [row] = await Self.rawSql( `SELECT Priv AS priv FROM mysql.global_priv WHERE User = ? AND Host = ?`, [mysqlUser, mysqlHost] ); const priv = row && JSON.parse(row.priv); const role = priv && priv.default_role; isUpdatable = !row || (role && role.startsWith('z-')); } if (!isUpdatable) { console.warn(`RoleConfig.syncUser(): User '${userName}' cannot be updated, not managed by me`); return; } if (info.hasAccount) { if (password) { if (!userExists) { await Self.rawSql('CREATE USER ?@? IDENTIFIED BY ?', [mysqlUser, mysqlHost, password] ); userExists = true; } else { switch (this.dbType) { case 'MariaDB': await Self.rawSql('ALTER USER ?@? IDENTIFIED BY ?', [mysqlUser, mysqlHost, password] ); break; default: await Self.rawSql('SET PASSWORD FOR ?@? = PASSWORD(?)', [mysqlUser, mysqlHost, password] ); } } } if (userExists && this.dbType == 'MariaDB') { let role = `z-${info.user.role().name}`; try { await Self.rawSql('REVOKE ALL, GRANT OPTION FROM ?@?', [mysqlUser, mysqlHost] ); } catch (err) { if (err.code == 'ER_REVOKE_GRANTS') console.warn(`${err.code}: ${err.sqlMessage}: ${err.sql}`); else throw err; } await Self.rawSql('GRANT ? TO ?@?', [role, mysqlUser, mysqlHost] ); if (role) { await Self.rawSql('SET DEFAULT ROLE ? FOR ?@?', [role, mysqlUser, mysqlHost] ); } else { await Self.rawSql('SET DEFAULT ROLE NONE FOR ?@?', [mysqlUser, mysqlHost] ); } } } else if (userExists) await Self.rawSql('DROP USER ?@?', [mysqlUser, mysqlHost]); } }); };