2023-09-27 10:57:15 +00:00
|
|
|
local FORMNAME = "fediauth-check"
|
|
|
|
local FORMNAMEFEDI = "fediauth-check-fedi"
|
2023-01-29 12:16:32 +00:00
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
-- time for fediauth code verification
|
|
|
|
local fediauth_time = 300
|
2023-01-29 12:16:32 +00:00
|
|
|
|
|
|
|
-- playername => start_time
|
2023-09-27 10:57:15 +00:00
|
|
|
local fediauth_sessions = {}
|
2023-01-29 12:16:32 +00:00
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
local formspecfediadd = "size[9,10]" ..
|
|
|
|
"label[1,7;Input your fediverse account handle]" ..
|
|
|
|
"image[1.5,0.6;7,7;fediverse.png]" ..
|
|
|
|
"field[1,9;4,1;fediverse_account_url;@nick@example.com;]" ..
|
|
|
|
"button[5,8.7;3,1;submit;Send code]"
|
|
|
|
|
|
|
|
local feditempstore = {}
|
2023-09-27 19:47:29 +00:00
|
|
|
local failed_counter = {}
|
2023-09-27 10:57:15 +00:00
|
|
|
|
|
|
|
minetest.register_entity("fediauth:checkmark", {
|
|
|
|
initial_properties = {
|
|
|
|
pointable = false,
|
|
|
|
armor_groups = { immortal = 1 },
|
|
|
|
visual = "sprite",
|
|
|
|
visual_size = {x = 0.5, y = 0.5},
|
|
|
|
textures = { "checkmark.png^[opacity:180" },
|
|
|
|
use_texture_alpha = true,
|
|
|
|
static_save = false,
|
|
|
|
glow = 5,
|
|
|
|
},
|
|
|
|
on_detach = function(self, parent) self.object:remove() end
|
|
|
|
})
|
|
|
|
|
|
|
|
function fediauth.verified_checkmark(player, verified)
|
|
|
|
local tag = player:get_player_name()
|
|
|
|
local props = player:get_properties()
|
|
|
|
if verified then
|
|
|
|
local obj = minetest.add_entity({x=0,y=2,z=0}, "fediauth:checkmark", nil)
|
|
|
|
obj:set_attach(player, "Head", {x = 0, y = 12, z = 0})
|
|
|
|
player:set_properties({nametag = props.nametag .. " [FEDI]", nametag_color = "#00ff00" })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Code formspec on join for fediauth enabled players
|
2023-01-29 12:16:32 +00:00
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
|
|
local playername = player:get_player_name()
|
2023-09-27 10:57:15 +00:00
|
|
|
if fediauth.is_player_bypassed(playername) then return end
|
|
|
|
if fediauth.is_player_enabled(playername) or minetest.settings:get_bool("fediauth.fedi_required", false) then
|
|
|
|
minetest.log("action", "[fediauth] session start for player: '" .. playername .. "'")
|
2023-01-30 17:06:06 +00:00
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
-- start fediauth session time
|
|
|
|
fediauth_sessions[player:get_player_name()] = os.time()
|
2023-01-29 12:16:32 +00:00
|
|
|
|
|
|
|
-- revoke important privs and re-grant again on code-verification
|
2023-09-27 10:57:15 +00:00
|
|
|
fediauth.revoke_privs(playername)
|
|
|
|
|
|
|
|
-- if fedi only allowed
|
|
|
|
if minetest.settings:get_bool("fediauth.fedi_required", false) then
|
|
|
|
local existsfedi = fediauth.storage:get_string(playername .. "_fedi")
|
|
|
|
if existsfedi == "" or not existsfedi then
|
|
|
|
minetest.log("action", "[fediauth] request fedi account for player: '" .. playername .. "'")
|
|
|
|
minetest.show_formspec(playername, FORMNAMEFEDI, formspecfediadd)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
2023-01-29 12:16:32 +00:00
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
local secret_b32 = fediauth.get_player_secret_b32(playername)
|
|
|
|
local codeseq = fediauth.give_code(secret_b32)
|
|
|
|
fediauth.send_code(codeseq[1], fediauth.storage:get_string(playername .. "_fedi"))
|
2023-01-29 12:16:32 +00:00
|
|
|
-- send verification formspec
|
|
|
|
local formspec = "size[10,2]" ..
|
2023-09-27 10:57:15 +00:00
|
|
|
"label[1,0;Please check your fedi account and enter code]" ..
|
2023-01-29 12:16:32 +00:00
|
|
|
"field[1,1.3;4,1;code;Code;]" ..
|
|
|
|
"button_exit[5,1;3,1;submit;Verify]"
|
|
|
|
|
|
|
|
minetest.show_formspec(playername, FORMNAME, formspec)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2023-09-27 19:47:29 +00:00
|
|
|
-- prevent flooding codes
|
|
|
|
minetest.register_on_prejoinplayer(function(name, ip)
|
|
|
|
if (failed_counter[name] or 0) >= 2 then
|
|
|
|
return "Please try later, your attempts has expired"
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
local function attempts_cleanup(name)
|
|
|
|
for k, v in pairs(failed_counter) do
|
|
|
|
if v >= 2 then
|
|
|
|
failed_counter[k] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
minetest.after(120, attempts_cleanup)
|
|
|
|
end
|
|
|
|
minetest.after(120, attempts_cleanup)
|
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
-- clear fediauth session on leave
|
2023-01-29 12:16:32 +00:00
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
|
|
local playername = player:get_player_name()
|
2023-09-27 10:57:15 +00:00
|
|
|
fediauth_sessions[playername] = nil
|
2023-01-29 12:16:32 +00:00
|
|
|
end)
|
|
|
|
|
|
|
|
-- check sessions periodically and kick if timed out
|
|
|
|
local function session_check()
|
|
|
|
local now = os.time()
|
2023-09-27 10:57:15 +00:00
|
|
|
for name, start_time in pairs(fediauth_sessions) do
|
|
|
|
if (now - start_time) > fediauth_time then
|
|
|
|
minetest.kick_player(name, "fediauth code validation timed out")
|
|
|
|
fediauth_sessions[name] = nil
|
2023-01-29 12:16:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
minetest.after(5, session_check)
|
|
|
|
end
|
|
|
|
minetest.after(5, session_check)
|
|
|
|
|
2023-09-27 10:57:15 +00:00
|
|
|
-- fediauth check
|
2023-01-29 12:16:32 +00:00
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
2023-09-27 10:57:15 +00:00
|
|
|
if formname ~= FORMNAME and formname ~= FORMNAMEFEDI then
|
2023-01-29 12:16:32 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local playername = player:get_player_name()
|
2023-09-27 10:57:15 +00:00
|
|
|
local secret_b32 = fediauth.get_player_secret_b32(playername)
|
|
|
|
|
|
|
|
-- check for new player or doesn't have fedi account
|
|
|
|
if fields.fediverse_account_url then
|
2023-09-27 19:47:29 +00:00
|
|
|
-- basic prevent mention spam and limit length
|
|
|
|
if not string.starts(fields.fediverse_account_url, "@") or string.len(fields.fediverse_account_url) < 3 or string.len(fields.fediverse_account_url) > 100 or fediauth.str_repeats(fields.fediverse_account_url, "@") > 2 then
|
2023-09-27 10:57:15 +00:00
|
|
|
minetest.chat_send_player(playername, minetest.colorize("#ff0000", "Try again, your input is incorrect"))
|
|
|
|
minetest.show_formspec(playername, FORMNAMEFEDI, formspecfediadd)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local secret_b32 = fediauth.get_player_secret_b32(playername)
|
|
|
|
local codeseq = fediauth.give_code(secret_b32)
|
|
|
|
fediauth.send_code(codeseq[1], fields.fediverse_account_url)
|
|
|
|
feditempstore[playername] = fields.fediverse_account_url
|
|
|
|
local formspec = "size[9,10]" ..
|
|
|
|
"label[1,7;Check code on " .. minetest.formspec_escape(fields.fediverse_account_url) .. "]" ..
|
|
|
|
"field[1,9;4,1;code;Code;]" ..
|
|
|
|
"button_exit[5,8.7;3,1;submit;Verify]"
|
|
|
|
|
|
|
|
minetest.show_formspec(playername, FORMNAME, formspec)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if fediauth.check_code(secret_b32, fields.code) then
|
|
|
|
local fedi_account = fediauth.storage:get_string(playername .. "_fedi")
|
|
|
|
|
2023-09-27 19:47:29 +00:00
|
|
|
-- if player without fediverse (for prevent write account handle if code incorrect)
|
2023-09-27 10:57:15 +00:00
|
|
|
if fedi_account == "" and feditempstore[playername] then
|
|
|
|
fediauth.storage:set_string(playername .. "_fedi", feditempstore[playername])
|
|
|
|
fedi_account = feditempstore[playername]
|
|
|
|
feditempstore[playername] = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
minetest.chat_send_player(playername, minetest.colorize("#00ff00", "fediauth code validation succeeded for " .. fedi_account))
|
|
|
|
fediauth_sessions[playername] = nil
|
|
|
|
fediauth.regrant_privs(playername)
|
|
|
|
fediauth.verified_checkmark(player, true)
|
2023-01-29 12:16:32 +00:00
|
|
|
else
|
2023-09-27 10:57:15 +00:00
|
|
|
minetest.kick_player(playername, "fediauth code validation failed")
|
|
|
|
fediauth.regrant_privs(playername)
|
2023-09-27 19:47:29 +00:00
|
|
|
failed_counter[playername] = (failed_counter[playername] or 0) + 1
|
2023-01-29 12:16:32 +00:00
|
|
|
end
|
2023-09-27 10:57:15 +00:00
|
|
|
end)
|