diff --git a/.luacheckrc b/.luacheckrc index 36b8c88..9038420 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -1,5 +1,8 @@ globals = { - "otp" + "otp", + "minetest" = { + "registered_privileges" + } } read_globals = { diff --git a/init.lua b/init.lua index 426cbdd..72f4061 100644 --- a/init.lua +++ b/init.lua @@ -18,6 +18,7 @@ dofile(MP.."/functions.lua") dofile(MP.."/onboard.lua") dofile(MP.."/join.lua") dofile(MP.."/privs.lua") +dofile(MP.."/priv_revoke.lua") if minetest.get_modpath("mtt") and mtt.enabled then dofile(MP.."/functions.spec.lua") diff --git a/join.lua b/join.lua index 941163b..83ef63a 100644 --- a/join.lua +++ b/join.lua @@ -6,62 +6,6 @@ local otp_time = 300 -- playername => start_time local otp_sessions = {} --- privs to revoke until the verification code is validated -local temp_revoke_privs = { - -- builtin - "interact", - "shout", - "privs", - "basic_privs", - "server", - "ban", - "kick", - "settime", - "password", - "protection_bypass", - -- we - "worldedit", - -- areas - "areas" -} - --- moves all "temp_revoke_privs" to mod-storage -local function revoke_privs(playername) - local privs = minetest.get_player_privs(playername) - if otp.storage:get_string(playername .. "_privs") == "" then - local moved_privs = {} - - for _, priv_name in ipairs(temp_revoke_privs) do - if privs[priv_name] then - privs[priv_name] = nil - moved_privs[priv_name] = true - end - end - - minetest.log("action", "[otp] revoking privs of '" .. playername .. "' list: " .. dump(moved_privs)) - minetest.set_player_privs(playername, privs) - otp.storage:set_string(playername .. "_privs", minetest.serialize(moved_privs)) - end -end - --- moves all privs from mod-storage into the live privs -local function regrant_privs(playername) - local stored_priv_str = otp.storage:get_string(playername .. "_privs") - if stored_priv_str ~= "" then - local privs = minetest.get_player_privs(playername) - local stored_privs = minetest.deserialize(stored_priv_str) - - -- merge stored privs into existing table - for priv_name in pairs(stored_privs) do - privs[priv_name] = true - end - - minetest.log("action", "[otp] regranting privs of '" .. playername .. "' list: " .. dump(stored_privs)) - minetest.set_player_privs(playername, privs) - otp.storage:set_string(playername .. "_privs", "") - end -end - -- Code formspec on join for otp enabled players minetest.register_on_joinplayer(function(player) local playername = player:get_player_name() @@ -72,7 +16,7 @@ minetest.register_on_joinplayer(function(player) otp_sessions[player:get_player_name()] = os.time() -- revoke important privs and re-grant again on code-verification - revoke_privs(playername) + otp.revoke_privs(playername) -- send verification formspec local formspec = "size[10,2]" .. @@ -115,8 +59,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if expected_code == fields.code then minetest.chat_send_player(playername, "OTP Code validation succeeded") otp_sessions[playername] = nil - regrant_privs(playername) + otp.regrant_privs(playername) else minetest.kick_player(playername, "OTP Code validation failed") + otp.regrant_privs(playername) end end) \ No newline at end of file diff --git a/priv_revoke.lua b/priv_revoke.lua new file mode 100644 index 0000000..0659013 --- /dev/null +++ b/priv_revoke.lua @@ -0,0 +1,58 @@ + +-- privs to revoke until the verification code is validated +local temp_revoke_privs = {} + +-- mark player health-related privs as "otp_keep" (they don't get removed while entering the otp code) +for _, name in ipairs({"fly", "noclip"}) do + local priv_def = minetest.registered_privileges[name] + if priv_def then + priv_def.otp_keep = true + end +end + +minetest.register_on_mods_loaded(function() + -- collect all privs to revoke while entering the otp code + for name, priv_def in pairs(minetest.registered_privileges) do + if not priv_def.otp_keep then + -- not marked explicitly as "keep" + table.insert(temp_revoke_privs, name) + end + end +end) + +-- moves all "temp_revoke_privs" to mod-storage +function otp.revoke_privs(playername) + local privs = minetest.get_player_privs(playername) + if otp.storage:get_string(playername .. "_privs") == "" then + local moved_privs = {} + + for _, priv_name in ipairs(temp_revoke_privs) do + if privs[priv_name] then + privs[priv_name] = nil + moved_privs[priv_name] = true + end + end + + minetest.log("action", "[otp] revoking privs of '" .. playername .. "' list: " .. dump(moved_privs)) + minetest.set_player_privs(playername, privs) + otp.storage:set_string(playername .. "_privs", minetest.serialize(moved_privs)) + end +end + +-- moves all privs from mod-storage into the live privs +function otp.regrant_privs(playername) + local stored_priv_str = otp.storage:get_string(playername .. "_privs") + if stored_priv_str ~= "" then + local privs = minetest.get_player_privs(playername) + local stored_privs = minetest.deserialize(stored_priv_str) + + -- merge stored privs into existing table + for priv_name in pairs(stored_privs) do + privs[priv_name] = true + end + + minetest.log("action", "[otp] regranting privs of '" .. playername .. "' list: " .. dump(stored_privs)) + minetest.set_player_privs(playername, privs) + otp.storage:set_string(playername .. "_privs", "") + end +end \ No newline at end of file diff --git a/privs.lua b/privs.lua index b8d7656..ab02a60 100644 --- a/privs.lua +++ b/privs.lua @@ -1,5 +1,6 @@ minetest.register_privilege("otp_enabled", { description = "otp enabled player", - give_to_singleplayer = false -}) \ No newline at end of file + give_to_singleplayer = false, + otp_keep = true +}) diff --git a/readme.md b/readme.md index db4013d..6b65dc6 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,21 @@ OTP verification form OTP Setup form ![](./screenshot2.png) +# Temporary privilege revocation + +All of the privileges get revoked when logging in with the otp enabled (until the proper code is entered). +Some exceptions: +* `fly` (otherwise the player would literally fall from the sky) +* `noclip` + +To disable revokation on custom privs the field `otp_keep` can be set to true on the definition: +```lua +minetest.register_privilege("my_super_important_priv", { + description = "something something", + otp_keep = true +}) +``` + # Links / References * https://en.wikipedia.org/wiki/Time-based_one-time_password