mod_http_file_share: Switch to new util.jwt API
authorMatthew Wild <mwild1@gmail.com>
Mon, 11 Jul 2022 13:49:47 +0100
changeset 12712 9953ac7b0c15
parent 12711 f75235110045
child 12713 b3f7c77c1f08
mod_http_file_share: Switch to new util.jwt API Some changes/improvements in this commit: - Default token lifetime is now 3600s (from 300s) - Tokens are only validated once per upload - "iat"/"exp" are handled automatically by util.jwt
plugins/mod_http_file_share.lua
--- a/plugins/mod_http_file_share.lua	Mon Jul 11 13:43:01 2022 +0100
+++ b/plugins/mod_http_file_share.lua	Mon Jul 11 13:49:47 2022 +0100
@@ -12,7 +12,6 @@
 local st = require "util.stanza";
 local url = require "socket.url";
 local dm = require "core.storagemanager".olddm;
-local jwt = require "util.jwt";
 local errors = require "util.error";
 local dataform = require "util.dataforms".new;
 local urlencode = require "util.http".urlencode;
@@ -44,6 +43,8 @@
 local daily_quota = module:get_option_number(module.name .. "_daily_quota", file_size_limit*10); -- 100 MB / day
 local total_storage_limit = module:get_option_number(module.name.."_global_quota", unlimited);
 
+local create_jwt, verify_jwt = require "util.jwt".init("HS256", secret);
+
 local access = module:get_option_set(module.name .. "_access", {});
 
 if not external_base_url then
@@ -169,16 +170,13 @@
 end
 
 function get_authz(slot, uploader, filename, filesize, filetype)
-local now = os.time();
-	return jwt.sign(secret, {
+	return create_jwt({
 		-- token properties
 		sub = uploader;
-		iat = now;
-		exp = now+300;
 
 		-- slot properties
 		slot = slot;
-		expires = expiry >= 0 and (now+expiry) or nil;
+		expires = expiry >= 0 and (os.time()+expiry) or nil;
 		-- file properties
 		filename = filename;
 		filesize = filesize;
@@ -249,32 +247,34 @@
 
 function handle_upload(event, path) -- PUT /upload/:slot
 	local request = event.request;
-	local authz = request.headers.authorization;
-	if authz then
-		authz = authz:match("^Bearer (.*)")
-	end
-	if not authz then
-		module:log("debug", "Missing or malformed Authorization header");
-		event.response.headers.www_authenticate = "Bearer";
-		return 401;
-	end
-	local authed, upload_info = jwt.verify(secret, authz);
-	if not (authed and type(upload_info) == "table" and type(upload_info.exp) == "number") then
-		module:log("debug", "Unauthorized or invalid token: %s, %q", authed, upload_info);
-		return 401;
-	end
-	if not request.body_sink and upload_info.exp < os.time() then
-		module:log("debug", "Authorization token expired on %s", dt.datetime(upload_info.exp));
-		return 410;
-	end
-	if not path or upload_info.slot ~= path:match("^[^/]+") then
-		module:log("debug", "Invalid upload slot: %q, path: %q", upload_info.slot, path);
-		return 400;
-	end
-	if request.headers.content_length and tonumber(request.headers.content_length) ~= upload_info.filesize then
-		return 413;
-		-- Note: We don't know the size if the upload is streamed in chunked encoding,
-		-- so we also check the final file size on completion.
+	local upload_info = request.http_file_share_upload_info;
+
+	if not upload_info then -- Initial handling of request
+		local authz = request.headers.authorization;
+		if authz then
+			authz = authz:match("^Bearer (.*)")
+		end
+		if not authz then
+			module:log("debug", "Missing or malformed Authorization header");
+			event.response.headers.www_authenticate = "Bearer";
+			return 401;
+		end
+		local authed, authed_upload_info = verify_jwt(authz);
+		if not authed then
+			module:log("debug", "Unauthorized or invalid token: %s, %q", authz, authed_upload_info);
+			return 401;
+		end
+		if not path or upload_info.slot ~= path:match("^[^/]+") then
+			module:log("debug", "Invalid upload slot: %q, path: %q", upload_info.slot, path);
+			return 400;
+		end
+		if request.headers.content_length and tonumber(request.headers.content_length) ~= upload_info.filesize then
+			return 413;
+			-- Note: We don't know the size if the upload is streamed in chunked encoding,
+			-- so we also check the final file size on completion.
+		end
+		upload_info = authed_upload_info;
+		request.http_file_share_upload_info = upload_info;
 	end
 
 	local filename = get_filename(upload_info.slot, true);