fed-sx-m1: Step 8c-post-auth — POST /activity bearer-token gate + route/2 + 13 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
-module(http_server).
|
||||
-export([route/1, ok_response/1, not_found_response/0,
|
||||
-export([route/1, route/2, ok_response/1, not_found_response/0,
|
||||
welcome_body/0, capabilities_body/0,
|
||||
capabilities_path/0,
|
||||
match_prefix/2, actors_prefix/0, actor_doc_response/1,
|
||||
artifacts_prefix/0, artifact_response/1,
|
||||
projections_list_path/0, projections_prefix/0,
|
||||
projections_list_response/0, projection_response/1]).
|
||||
projections_list_response/0, projection_response/1,
|
||||
activity_path/0, unauthorized_response/0,
|
||||
post_activity_response/0]).
|
||||
|
||||
%% HTTP request router per design §16.1.
|
||||
%%
|
||||
@@ -26,9 +28,21 @@
|
||||
%% `<<"GET">>` truncates to a single byte in this port.
|
||||
|
||||
route(Req) ->
|
||||
route(Req, []).
|
||||
|
||||
%% route/2 — Cfg proplist carries optional `:publish_token` (binary)
|
||||
%% for POST /activity auth. Other state (logs, projections, etc.) is
|
||||
%% not yet threaded through — POST /activity returns a stub 200
|
||||
%% once auth succeeds; real outbox:publish glue lands separately.
|
||||
route(Req, Cfg) ->
|
||||
M = field(method, Req),
|
||||
P = field(path, Req),
|
||||
dispatch(M, P).
|
||||
case {M, P} of
|
||||
{<<80,79,83,84>>, <<47,97,99,116,105,118,105,116,121>>} ->
|
||||
handle_post_activity(Req, Cfg);
|
||||
_ ->
|
||||
dispatch(M, P)
|
||||
end.
|
||||
|
||||
%% 71 69 84 = "GET" | 47 = "/"
|
||||
dispatch(<<71, 69, 84>>, <<47>>) ->
|
||||
@@ -161,3 +175,74 @@ projection_response(Name) ->
|
||||
Pre = <<112,114,111,106,101,99,116,105,111,110,58,32>>,
|
||||
Body = <<Pre/binary, Name/binary, 10>>,
|
||||
ok_response(Body).
|
||||
|
||||
%% "/activity" — 9 bytes
|
||||
activity_path() ->
|
||||
<<47,97,99,116,105,118,105,116,121>>.
|
||||
|
||||
%% 401 Unauthorized response. Body: "unauthorized\n" = 13 bytes.
|
||||
unauthorized_response() ->
|
||||
[{status, 401}, {headers, []},
|
||||
{body, <<117,110,97,117,116,104,111,114,105,122,101,100,10>>}].
|
||||
|
||||
%% Stub success body for POST /activity. Real impl will return
|
||||
%% the published activity's CID once outbox:publish is wired
|
||||
%% through a server-state context (Step 8c-post-publish).
|
||||
post_activity_response() ->
|
||||
%% "published (stub)\n" — hand-spelled
|
||||
Body = <<112,117,98,108,105,115,104,101,100,32,
|
||||
40,115,116,117,98,41,10>>,
|
||||
ok_response(Body).
|
||||
|
||||
%% Auth helpers.
|
||||
|
||||
handle_post_activity(Req, Cfg) ->
|
||||
case check_bearer(Req, Cfg) of
|
||||
ok ->
|
||||
post_activity_response();
|
||||
{error, _} ->
|
||||
unauthorized_response()
|
||||
end.
|
||||
|
||||
check_bearer(Req, Cfg) ->
|
||||
case bearer_token(Req) of
|
||||
{ok, Got} ->
|
||||
case expected_token(Cfg) of
|
||||
{ok, Want} when Got =:= Want -> ok;
|
||||
_ -> {error, bad_token}
|
||||
end;
|
||||
not_found -> {error, no_auth}
|
||||
end.
|
||||
|
||||
%% Look up the Authorization header, strip "Bearer ", return token.
|
||||
bearer_token(Req) ->
|
||||
case field(headers, Req) of
|
||||
nil -> not_found;
|
||||
Hs ->
|
||||
%% "authorization" — 13 bytes, lowercase as the BIF wrapper
|
||||
%% normalises headers to lowercase keys.
|
||||
AuthKey = <<97,117,116,104,111,114,105,122,97,116,105,111,110>>,
|
||||
case find_header(AuthKey, Hs) of
|
||||
not_found -> not_found;
|
||||
{ok, V} -> strip_bearer(V)
|
||||
end
|
||||
end.
|
||||
|
||||
find_header(_, []) -> not_found;
|
||||
find_header(K, [{K, V} | _]) -> {ok, V};
|
||||
find_header(K, [_ | Rest]) -> find_header(K, Rest).
|
||||
|
||||
%% "Bearer " — 7 bytes — strip and return the rest as the token.
|
||||
%% Anything else returns not_found (treated as missing auth).
|
||||
strip_bearer(V) ->
|
||||
Prefix = <<66,101,97,114,101,114,32>>,
|
||||
case match_prefix(Prefix, V) of
|
||||
{ok, Token} when byte_size(Token) > 0 -> {ok, Token};
|
||||
_ -> not_found
|
||||
end.
|
||||
|
||||
expected_token(Cfg) ->
|
||||
case field(publish_token, Cfg) of
|
||||
nil -> not_found;
|
||||
T -> {ok, T}
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user