qr code gen

This commit is contained in:
BuckarooBanzay 2023-01-28 19:37:27 +01:00
parent e0d58ad2ec
commit 02f90efcaa
4 changed files with 68 additions and 23 deletions

View file

@ -110,8 +110,22 @@ function otp.hmac(key, message)
return hmac
end
function otp.generate_code(key, message)
local hmac = otp.hmac(key, message)
local function left_pad(str, s, len)
while #str < len do
str = s .. str
end
return str
end
function otp.generate_totp(key, unix_time)
unix_time = unix_time or os.time()
local tx = 30
local ct = math.floor(unix_time / tx)
local counter = otp.write_uint64_be(ct)
local valid_seconds = ((ct * tx) + tx) - unix_time
local hmac = otp.hmac(key, counter)
-- https://www.rfc-editor.org/rfc/rfc4226#section-5.4
local offset = bitand(string.byte(hmac, #hmac), 0xF)
@ -120,5 +134,33 @@ function otp.generate_code(key, message)
value = bitor(value, lshift(string.byte(hmac, offset+3), 8))
value = bitor(value, lshift(string.byte(hmac, offset+2), 16))
value = bitor(value, lshift(bitand(string.byte(hmac, offset+1), 0x7F), 24))
return value % 10^6
local code = value % 10^6
local padded_code = left_pad("" .. code, "0", 6)
return padded_code, valid_seconds
end
function otp.create_qr_png(data)
local pixel_size = 3
local height = pixel_size * #data
local width = height
local png_data = {}
for _, row in ipairs(data) do
assert(#row == #data)
for _=1,pixel_size do
for _, v in ipairs(row) do
for _=1,pixel_size do
if v > 0 then
table.insert(png_data, 0xFF000000)
else
table.insert(png_data, 0xFFFFFFFF)
end
end
end
end
end
assert(#png_data == width*height)
return minetest.encode_png(width, height, png_data, 2)
end

View file

@ -27,17 +27,34 @@ mtt.register("otp.hmac", function(callback)
callback()
end)
mtt.register("otp.generate_code", function(callback)
mtt.register("otp.generate_totp", function(callback)
local expected_code = 699847
local secret_b32 = "N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
local secret = otp.basexx.from_base32(secret_b32)
local unix_time = 1640995200
local tx = 30
local ct = math.floor(unix_time / tx)
local counter = otp.write_uint64_be(ct)
local code, valid_seconds = otp.generate_totp(secret, unix_time)
assert(code == ""..expected_code)
assert(valid_seconds > 0)
local code = otp.generate_code(secret, counter)
assert(code == expected_code)
code, valid_seconds = otp.generate_totp(secret)
print("Current code: " .. code .. " valid for " .. valid_seconds .. " seconds")
callback()
end)
mtt.register("otp.create_qr_png", function(callback)
local url = "otpauth://totp/abc:myaccount?algorithm=SHA1&digits=6&issuer=abc&period=30&"
.. "secret=N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
local ok, code = otp.qrcode(url)
assert(ok)
assert(code)
local png = otp.create_qr_png(code)
assert(png)
local f = io.open(minetest.get_worldpath() .. "/qr.png", "w")
f:write(png)
f:close()
callback()
end)

View file

@ -15,5 +15,4 @@ dofile(MP.."/functions.lua")
if minetest.get_modpath("mtt") and mtt.enabled then
dofile(MP.."/functions.spec.lua")
dofile(MP.."/qrencode.spec.lua")
end

View file

@ -1,13 +0,0 @@
mtt.register("otp.qrcode", function(callback)
assert(type(otp.qrcode) == "function")
local url = "otpauth://totp/abc:myaccount?algorithm=SHA1&digits=6&issuer=abc&period=30&"
.. "secret=N6JGKMEKU2E6HQMLLNMJKBRRGVQ2ZKV7"
local ok, code = otp.qrcode(url)
assert(ok)
assert(code)
callback()
end)