File

util/jwt.lua @ 12094:84fd6a79cda7

adminstream: fire disconnected event on lower layer disconnect This may in theory cause multiple disconnect events for the adminstream client, if the only code using that wasn't calling os.exit right away. Hence, this should be a good enough partial fix for #1671. It is not a full fix, because the shell will only notice the disconnect after one has hit enter in the input; until then, it is stuck in a read() call to stdin and completely oblivious to the disconnect.
author Jonas Schäfer <jonas@wielicki.name>
date Tue, 21 Dec 2021 21:23:01 +0100
parent 11561:d2f33b8fdc96
child 12696:27a72982e331
line wrap: on
line source

local s_gsub = string.gsub;
local json = require "util.json";
local hashes = require "util.hashes";
local base64_encode = require "util.encodings".base64.encode;
local base64_decode = require "util.encodings".base64.decode;
local secure_equals = require "util.hashes".equals;

local b64url_rep = { ["+"] = "-", ["/"] = "_", ["="] = "", ["-"] = "+", ["_"] = "/" };
local function b64url(data)
	return (s_gsub(base64_encode(data), "[+/=]", b64url_rep));
end
local function unb64url(data)
	return base64_decode(s_gsub(data, "[-_]", b64url_rep).."==");
end

local static_header = b64url('{"alg":"HS256","typ":"JWT"}') .. '.';

local function sign(key, payload)
	local encoded_payload = json.encode(payload);
	local signed = static_header .. b64url(encoded_payload);
	local signature = hashes.hmac_sha256(key, signed);
	return signed .. "." .. b64url(signature);
end

local jwt_pattern = "^(([A-Za-z0-9-_]+)%.([A-Za-z0-9-_]+))%.([A-Za-z0-9-_]+)$"
local function verify(key, blob)
	local signed, bheader, bpayload, signature = string.match(blob, jwt_pattern);
	if not signed then
		return nil, "invalid-encoding";
	end
	local header = json.decode(unb64url(bheader));
	if not header or type(header) ~= "table" then
		return nil, "invalid-header";
	elseif header.alg ~= "HS256" then
		return nil, "unsupported-algorithm";
	end
	if not secure_equals(b64url(hashes.hmac_sha256(key, signed)), signature) then
		return false, "signature-mismatch";
	end
	local payload, err = json.decode(unb64url(bpayload));
	if err ~= nil then
		return nil, "json-decode-error";
	end
	return true, payload;
end

return {
	sign = sign;
	verify = verify;
};