From 8977ba41cbddbc97d1d0e4991c7dc3ad38cc2df8 Mon Sep 17 00:00:00 2001 From: Timo Smit Date: Fri, 13 Jan 2017 18:59:14 +0100 Subject: [PATCH] Implemented basic ACL functionality (issue #69) --- database/new/wolfadmin_sqlite.sql | 96 ++++++++++++++++++++++++++ luascripts/auth/acl.lua | 30 +++++--- luascripts/commands/admin/setlevel.lua | 2 +- luascripts/db/sqlite3.lua | 39 ++++++++++- 4 files changed, 155 insertions(+), 12 deletions(-) diff --git a/database/new/wolfadmin_sqlite.sql b/database/new/wolfadmin_sqlite.sql index bf66b2b..1ce8620 100644 --- a/database/new/wolfadmin_sqlite.sql +++ b/database/new/wolfadmin_sqlite.sql @@ -3,6 +3,13 @@ CREATE TABLE IF NOT EXISTS `level` ( `name` TEXT NOT NULL ); +CREATE TABLE `level_role` ( + `level_id` INTEGER NOT NULL, + `role` TEXT NOT NULL, + PRIMARY KEY (`level_id`, `role`), + CONSTRAINT `role_level` FOREIGN KEY (`level_id`) REFERENCES `level` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION +); + CREATE TABLE IF NOT EXISTS `player` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `guid` TEXT NOT NULL UNIQUE, @@ -100,5 +107,94 @@ CREATE INDEX IF NOT EXISTS `record_player_idx` ON `record` (`player_id`); INSERT INTO `level` (`id`, `name`) VALUES (0, 'Guest'); INSERT INTO `level` (`id`, `name`) VALUES (5, 'Admin'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'admintest'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'help'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'time'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'greeting'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'listmaps'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'listsprees'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'listrules'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (0, 'adminchat'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'admintest'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'help'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'time'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'greeting'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listplayers'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listteams'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listmaps'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listsprees'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listrules'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listhistory'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listwarns'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listbans'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listaliases'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'listlevels'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'liststats'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'finger'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'adminchat'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'put'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'dropweapons'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'rename'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'freeze'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'disorient'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'burn'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'slap'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'gib'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'throw'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'glow'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'pants'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'pop'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'warn'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'mute'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'voicemute'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'kick'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'ban'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'spec999'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'balance'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'lockplayers'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'lockteam'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'shuffle'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'swap'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'pause'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'nextmap'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'restart'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'botadmin'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'enablevote'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'cancelvote'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'passvote'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'news'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'uptime'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'setlevel'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'readconfig'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'noinactivity'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'novote'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'nocensor'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'nobalance'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'novotelimit'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'noreason'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'perma'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'teamcmds'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'silentcmds'); + +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'spy'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'incognito'); +INSERT INTO `level_role`(`level_id`, `role`) VALUES (5, 'immune'); + INSERT INTO `player` (`id`, `guid`, `ip`, `level`) VALUES (1, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', '127.0.0.1', 5); INSERT INTO `alias` (`id`, `player_id`, `alias`, `cleanalias`, `lastused`, `used`) VALUES (1, 1, 'console', 'console', 0, 0); \ No newline at end of file diff --git a/luascripts/auth/acl.lua b/luascripts/auth/acl.lua index 8e1971d..c981134 100644 --- a/luascripts/auth/acl.lua +++ b/luascripts/auth/acl.lua @@ -23,27 +23,41 @@ local players = require "luascripts.wolfadmin.players.players" local events = require "luascripts.wolfadmin.util.events" local files = require "luascripts.wolfadmin.util.files" +local tables = require "luascripts.wolfadmin.util.tables" local acl = {} -function acl.readpermissions() +local data = {} + +function acl.readPermissions() -- read level permissions into a cache file (can be loaded at mod start) -- should probably cache current players' permissions as well, then -- read in new players' permissions as they join the server -end -function acl.clearcache() + local roles = db.getLevelRoles() + + for _, role in ipairs(roles) do + if not data[role["level_id"]] then + data[role["level_id"]] = {} + end + + table.insert(data[role["level_id"]], role["role"]) + end +end +events.handle("onGameInit", acl.readPermissions) + +function acl.clearCache() -- clear cache whenever database is updated, or do this manually end function acl.isallowed(clientId, permission) - -- stub function, reads from cache + local level = acl.getlevel(clientId) - if permission == auth.PERM_IMMUNE or permission == "!" then - return 0 + if data[level] ~= nil and tables.contains(data[level], permission) then + return 1 end - return 1 + return 0 end function acl.getlevel(clientId) @@ -53,7 +67,7 @@ function acl.getlevel(clientId) end function acl.getlevelname(levelId) - local level = db.getlevel(levelId) + local level = db.getLevel(levelId) return level["name"] end diff --git a/luascripts/commands/admin/setlevel.lua b/luascripts/commands/admin/setlevel.lua index 1c4ff60..48550e7 100644 --- a/luascripts/commands/admin/setlevel.lua +++ b/luascripts/commands/admin/setlevel.lua @@ -69,7 +69,7 @@ function commandSetLevel(clientId, cmdArguments) et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dsetlevel: ^9sorry, but your intended victim has a higher admin level than you do.\";") return true - elseif not db.getlevel(tonumber(cmdArguments[2])) then + elseif not db.getLevel(tonumber(cmdArguments[2])) then et.trap_SendConsoleCommand(et.EXEC_APPEND, "csay "..clientId.." \"^dsetlevel: ^9this admin level does not exist.\";") return true diff --git a/luascripts/db/sqlite3.lua b/luascripts/db/sqlite3.lua index 7aa528e..5b4ed22 100644 --- a/luascripts/db/sqlite3.lua +++ b/luascripts/db/sqlite3.lua @@ -57,15 +57,31 @@ function sqlite3.getplayer(guid) end -- levels -function sqlite3.addlevel(id, name) +function sqlite3.addLevel(id, name) cur = assert(con:execute("INSERT INTO `level` (`id`, `name`) VALUES ('"..tonumber(id).."', '"..util.escape(name).."')")) end -function sqlite3.updatelevel(id, name) +function sqlite3.updateLevel(id, name) cur = assert(con:execute("UPDATE `level` SET `name`='"..util.escape(name).."' WHERE `id`='"..tonumber(id).."'")) end -function sqlite3.getlevel(id) +function sqlite3.getLevels() + cur = assert(con:execute("SELECT * FROM `level`")) + + local levels = {} + local row = cur:fetch({}, "a") + + while row do + table.insert(levels, tables.copy(row)) + row = cur:fetch(row, "a") + end + + cur:close() + + return levels +end + +function sqlite3.getLevel(id) cur = assert(con:execute("SELECT * FROM `level` WHERE `id`='"..tonumber(id).."'")) local level = cur:fetch({}, "a") @@ -74,6 +90,23 @@ function sqlite3.getlevel(id) return level end +-- acl +function sqlite3.getLevelRoles() + cur = assert(con:execute("SELECT * FROM `level_role`")) + + local roles = {} + local row = cur:fetch({}, "a") + + while row do + table.insert(roles, tables.copy(row)) + row = cur:fetch(row, "a") + end + + cur:close() + + return roles +end + -- aliases function sqlite3.addalias(playerid, alias, lastused) cur = assert(con:execute("INSERT INTO `alias` (`player_id`, `alias`, `cleanalias`, `lastused`, `used`) VALUES ("..tonumber(playerid)..", '"..util.escape(alias).."', '"..util.escape(util.removeColors(alias)).."', "..tonumber(lastused)..", 1)"))