mirror of
https://git.phreedom.club/localhost_frssoft/fediauth.git
synced 2024-11-29 11:21:28 +00:00
onboard form and join check
This commit is contained in:
parent
bb06a28048
commit
9f3633ea58
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -17,4 +17,4 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: test
|
- name: test
|
||||||
run: docker-compose up --exit-code-from test
|
run: docker-compose up --exit-code-from test test
|
||||||
|
|
45
auth.lua
45
auth.lua
|
@ -1,15 +1,46 @@
|
||||||
-- TODO
|
-- builtin auth handler
|
||||||
|
|
||||||
local auth_handler = minetest.get_auth_handler()
|
local auth_handler = minetest.get_auth_handler()
|
||||||
|
|
||||||
local old_get_auth = auth_handler.get_auth
|
local old_get_auth = auth_handler.get_auth
|
||||||
|
|
||||||
|
-- time for otp to be enabled until properly logged in
|
||||||
|
local otp_time = 300
|
||||||
|
|
||||||
|
-- playername => start_time
|
||||||
|
local otp_sessions = {}
|
||||||
|
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
-- reset otp session upon login
|
||||||
|
local playername = player:get_player_name()
|
||||||
|
otp_sessions[player:get_player_name()] = nil
|
||||||
|
print("minetest.register_on_joinplayer(" .. playername .. ")")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- override "get_auth" from builtin auth handler
|
||||||
auth_handler.get_auth = function(name)
|
auth_handler.get_auth = function(name)
|
||||||
local auth = old_get_auth(name)
|
local auth = old_get_auth(name)
|
||||||
|
|
||||||
if name ~= "singleplayer" then
|
print("auth_handler.get_auth(" .. name .. ")")
|
||||||
-- replace runtime password with legacy password hash
|
if name == "singleplayer" or not auth.privileges.otp_enabled then
|
||||||
auth.password = minetest.get_password_hash(name, "enter")
|
-- singleplayer or otp not set up
|
||||||
end
|
|
||||||
return auth
|
return auth
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- minetest.disconnect_player(name, "something, something")
|
||||||
|
|
||||||
|
local now = os.time()
|
||||||
|
local otp_session = otp_sessions[name]
|
||||||
|
if not otp_session or (now - otp_session) > otp_time then
|
||||||
|
-- otp session expired or not set up
|
||||||
|
otp_sessions[name] = now
|
||||||
|
end
|
||||||
|
|
||||||
|
-- replace runtime password with legacy password hash
|
||||||
|
--auth.password = minetest.get_password_hash(name, "enter")
|
||||||
|
|
||||||
|
return auth
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_prejoinplayer(function(name)
|
||||||
|
print("minetest.register_on_prejoinplayer(" .. name .. ")")
|
||||||
|
|
||||||
|
end)
|
|
@ -8,8 +8,15 @@ services:
|
||||||
- "./:/root/.minetest/worlds/world/worldmods/otp/"
|
- "./:/root/.minetest/worlds/world/worldmods/otp/"
|
||||||
- "./test/minetest.conf:/minetest.conf"
|
- "./test/minetest.conf:/minetest.conf"
|
||||||
- "world:/root/.minetest/worlds/world"
|
- "world:/root/.minetest/worlds/world"
|
||||||
|
|
||||||
|
minetest:
|
||||||
|
image: registry.gitlab.com/minetest/minetest/server:5.6.1
|
||||||
|
user: root
|
||||||
ports:
|
ports:
|
||||||
- "30000:30000/udp"
|
- "30000:30000/udp"
|
||||||
|
volumes:
|
||||||
|
- "./:/root/.minetest/worlds/world/worldmods/otp/"
|
||||||
|
- "world:/root/.minetest/worlds/world"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
world: {}
|
world: {}
|
|
@ -117,7 +117,8 @@ local function left_pad(str, s, len)
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
function otp.generate_totp(key, unix_time)
|
function otp.generate_totp(secret_b32, unix_time)
|
||||||
|
local key = otp.basexx.from_base32(secret_b32)
|
||||||
unix_time = unix_time or os.time()
|
unix_time = unix_time or os.time()
|
||||||
|
|
||||||
local tx = 30
|
local tx = 30
|
||||||
|
@ -168,3 +169,13 @@ function otp.generate_secret()
|
||||||
end
|
end
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- get or generate per-player secret b32 ecoded
|
||||||
|
function otp.get_player_secret_b32(name)
|
||||||
|
local secret_b32 = otp.storage:get_string(name .. "_secret")
|
||||||
|
if secret_b32 == "" then
|
||||||
|
secret_b32 = otp.basexx.to_base32(otp.generate_secret())
|
||||||
|
otp.storage:set_string(name .. "_secret", secret_b32)
|
||||||
|
end
|
||||||
|
return secret_b32
|
||||||
|
end
|
|
@ -30,14 +30,13 @@ end)
|
||||||
mtt.register("otp.generate_totp", function(callback)
|
mtt.register("otp.generate_totp", function(callback)
|
||||||
local expected_code = 699847
|
local expected_code = 699847
|
||||||
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
|
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
|
||||||
local secret = otp.basexx.from_base32(secret_b32)
|
|
||||||
local unix_time = 1640995200
|
local unix_time = 1640995200
|
||||||
|
|
||||||
local code, valid_seconds = otp.generate_totp(secret, unix_time)
|
local code, valid_seconds = otp.generate_totp(secret_b32, unix_time)
|
||||||
assert(code == ""..expected_code)
|
assert(code == ""..expected_code)
|
||||||
assert(valid_seconds > 0)
|
assert(valid_seconds > 0)
|
||||||
|
|
||||||
code, valid_seconds = otp.generate_totp(secret)
|
code, valid_seconds = otp.generate_totp(secret_b32)
|
||||||
print("Current code: " .. code .. " valid for " .. valid_seconds .. " seconds")
|
print("Current code: " .. code .. " valid for " .. valid_seconds .. " seconds")
|
||||||
callback()
|
callback()
|
||||||
end)
|
end)
|
||||||
|
|
1
init.lua
1
init.lua
|
@ -14,6 +14,7 @@ otp = {
|
||||||
dofile(MP.."/functions.lua")
|
dofile(MP.."/functions.lua")
|
||||||
dofile(MP.."/onboard.lua")
|
dofile(MP.."/onboard.lua")
|
||||||
dofile(MP.."/auth.lua")
|
dofile(MP.."/auth.lua")
|
||||||
|
dofile(MP.."/privs.lua")
|
||||||
|
|
||||||
if minetest.get_modpath("mtt") and mtt.enabled then
|
if minetest.get_modpath("mtt") and mtt.enabled then
|
||||||
dofile(MP.."/functions.spec.lua")
|
dofile(MP.."/functions.spec.lua")
|
||||||
|
|
38
onboard.lua
38
onboard.lua
|
@ -1,10 +1,23 @@
|
||||||
local FORMNAME = "otp-enable"
|
local FORMNAME = "otp-enable"
|
||||||
|
|
||||||
local secret = otp.generate_secret()
|
minetest.register_chatcommand("otp_disable", {
|
||||||
local secret_b32 = otp.basexx.to_base32(secret)
|
privs = { otp_enabled = true },
|
||||||
|
func = function(name)
|
||||||
|
-- clear priv
|
||||||
|
local privs = minetest.get_player_privs(name)
|
||||||
|
privs.otp_enabled = true
|
||||||
|
minetest.set_player_privs(name, privs)
|
||||||
|
return true, "OTP login disabled"
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand("otp_enable", {
|
minetest.register_chatcommand("otp_enable", {
|
||||||
func = function(name)
|
func = function(name)
|
||||||
|
if name == "singleplayer" then
|
||||||
|
return false, "OTP not available in singleplayer"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- issuer name
|
||||||
local issuer = "Minetest"
|
local issuer = "Minetest"
|
||||||
if minetest.settings:get("server_name") ~= "" then
|
if minetest.settings:get("server_name") ~= "" then
|
||||||
issuer = minetest.settings:get("server_name")
|
issuer = minetest.settings:get("server_name")
|
||||||
|
@ -12,12 +25,17 @@ minetest.register_chatcommand("otp_enable", {
|
||||||
issuer = minetest.settings:get("server_address")
|
issuer = minetest.settings:get("server_address")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local secret_b32 = otp.get_player_secret_b32(name)
|
||||||
|
|
||||||
|
-- url for the qr code
|
||||||
local url = "otpauth://totp/" .. issuer .. ":" .. name .. "?algorithm=SHA1&" ..
|
local url = "otpauth://totp/" .. issuer .. ":" .. name .. "?algorithm=SHA1&" ..
|
||||||
"digits=6&issuer=" .. issuer .. "&period=30&" ..
|
"digits=6&issuer=" .. issuer .. "&period=30&" ..
|
||||||
"secret=" .. secret_b32
|
"secret=" .. secret_b32
|
||||||
|
|
||||||
local ok, code = otp.qrcode(url)
|
local ok, code = otp.qrcode(url)
|
||||||
assert(ok)
|
if not ok then
|
||||||
|
return false, "qr code generation failed"
|
||||||
|
end
|
||||||
|
|
||||||
local png = otp.create_qr_png(code)
|
local png = otp.create_qr_png(code)
|
||||||
local formspec = "size[10,10]" ..
|
local formspec = "size[10,10]" ..
|
||||||
|
@ -34,12 +52,18 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.code then
|
if fields.code then
|
||||||
print("Validating code for " .. player:get_player_name())
|
local playername = player:get_player_name()
|
||||||
local expected_code = otp.generate_totp(secret)
|
local secret_b32 = otp.get_player_secret_b32(playername)
|
||||||
|
local expected_code = otp.generate_totp(secret_b32)
|
||||||
if expected_code == fields.code then
|
if expected_code == fields.code then
|
||||||
print("Valid")
|
-- set priv
|
||||||
|
local privs = minetest.get_player_privs(playername)
|
||||||
|
privs.otp_enabled = true
|
||||||
|
minetest.set_player_privs(playername, privs)
|
||||||
|
|
||||||
|
minetest.chat_send_player(playername, "Code validation succeeded, OTP login enabled")
|
||||||
else
|
else
|
||||||
print("Invalid")
|
minetest.chat_send_player(playername, "Code validation failed!")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue