<commit_before>%%%-------------------------------------------------------------------
%%% This file is part of the CernVM File System.
%%%
%%% @doc cvmfs_payloads_handler - request handler for the "payloads"
%%%                               resource
%%%
%%% @end
%%%-------------------------------------------------------------------

-module(cvmfs_payloads_handler).

-export([init/2]).

%%--------------------------------------------------------------------
%% @doc
%% Handles requests for the /api/payloads resource
%%
%% @end
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%% @doc
%% A "GET" request to /api/payloads returns 405 - method not allowed
%% @end
%%--------------------------------------------------------------------
init(Req0 = #{method := <<"GET">>}, State) ->
    {URI, T0} = cvmfs_fe_util:tick(Req0, micro_seconds),

    Req1 = cowboy_req:reply(405,
                           #{<<"content-type">> => <<"application/plain-text">>},
                           <<"">>,
                           Req0),

    cvmfs_fe_util:tock(URI, T0, micro_seconds),
    {ok, Req1, State};
%% @doc
%% A "POST" request to /api/payloads, which can return either 200 OK
%% or in 400 - Bad Request
%%
%% The body of the request should be a JSON payload containing the
%% "session_token" and "payload" fields.
%% The request needs two specific fields in the header:
%%   "authorization" - KeyId and HMAC of the request body (the JSON object)
%%                     The KeyId and HMAC should be separated by a space
%%   "message-size" - the size of the JSON object
%%
%% The body of the reply, for a valid request contains the fields:
%% "status" - either "ok", "error"
%% "reason" - if status is "error", this is a description of the error.
%% @end
%%--------------------------------------------------------------------
init(Req0 = #{method := <<"POST">>}, State) ->
    {_, T0} = cvmfs_fe_util:tick(Req0, micro_seconds),

    #{headers := #{<<"authorization">> := Auth, <<"message-size">> := MessageSizeBin}} = Req0,
    [KeyId, ClientHMAC] = binary:split(Auth, <<" ">>),
    MessageSize = binary_to_integer(MessageSizeBin),
    {ok, Data, Req1} = cvmfs_fe_util:read_body(Req0),
    <<JSONMessage:MessageSize/binary,Payload/binary>> = Data,
    {Status, Reply, Req2} = case jsx:decode(JSONMessage, [return_maps]) of
                                #{<<"session_token">> := Token} ->
                                    Rep = case cvmfs_auth:check_hmac(JSONMessage, KeyId, ClientHMAC) of
                                              true ->
                                                  p_submit_payload(Token, Payload);
                                              false ->
                                                  #{<<"status">> => <<"error">>,
                                                    <<"reason">> => <<"invalid_hmac">>}
                                    end,
                                    {200, Rep, Req1};
                                _ ->
                                    {400, #{}, Req0}
                            end,
    ReqF = cowboy_req:reply(Status,
                            #{<<"content-type">> => <<"application/json">>},
                            jsx:encode(Reply),
                            Req2),

    cvmfs_fe_util:tock(<<"payload_not_shown">>, T0, micro_seconds),
    {ok, ReqF, State}.


%% Private functions


p_submit_payload(Token, Payload) ->
    case cvmfs_be:submit_payload(Token, Payload) of
        {ok, payload_added} ->
            #{<<"status">> => <<"ok">>};
        {error, Reason} ->
            #{<<"status">> => <<"error">>, <<"reason">> => atom_to_binary(Reason, latin1)}
    end.

<commit_msg>Updating payload submission API documentation<commit_after>%%%-------------------------------------------------------------------
%%% This file is part of the CernVM File System.
%%%
%%% @doc cvmfs_payloads_handler - request handler for the "payloads"
%%%                               resource
%%%
%%% @end
%%%-------------------------------------------------------------------

-module(cvmfs_payloads_handler).

-export([init/2]).

%%--------------------------------------------------------------------
%% @doc
%% Handles requests for the /api/payloads resource
%%
%% @end
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%% @doc
%% A "GET" request to /api/payloads returns 405 - method not allowed
%% @end
%%--------------------------------------------------------------------
init(Req0 = #{method := <<"GET">>}, State) ->
    {URI, T0} = cvmfs_fe_util:tick(Req0, micro_seconds),

    Req1 = cowboy_req:reply(405,
                           #{<<"content-type">> => <<"application/plain-text">>},
                           <<"">>,
                           Req0),

    cvmfs_fe_util:tock(URI, T0, micro_seconds),
    {ok, Req1, State};
%% @doc
%% A "POST" request to /api/payloads, which can return either 200 OK
%% or in 400 - Bad Request
%%
%% The body of the request should be a JSON message containing the
%% "session_token" field. Directly after the JSON message, representing the
%% remainder of the request body, there is the payload (serialized ObjectPack
%% produced by the CVMFS server tools)
%% The request needs two specific fields in the header:
%%   "authorization" - KeyId and HMAC of the request body (the JSON object)
%%                     The KeyId and HMAC should be separated by a space
%%   "message-size" - the size of the JSON object
%%
%% The body of the reply, for a valid request contains the fields:
%% "status" - either "ok", "error"
%% "reason" - if status is "error", this is a description of the error.
%% @end
%%--------------------------------------------------------------------
init(Req0 = #{method := <<"POST">>}, State) ->
    {_, T0} = cvmfs_fe_util:tick(Req0, micro_seconds),

    #{headers := #{<<"authorization">> := Auth, <<"message-size">> := MessageSizeBin}} = Req0,
    [KeyId, ClientHMAC] = binary:split(Auth, <<" ">>),
    MessageSize = binary_to_integer(MessageSizeBin),
    {ok, Data, Req1} = cvmfs_fe_util:read_body(Req0),
    <<JSONMessage:MessageSize/binary,Payload/binary>> = Data,
    {Status, Reply, Req2} = case jsx:decode(JSONMessage, [return_maps]) of
                                #{<<"session_token">> := Token} ->
                                    Rep = case cvmfs_auth:check_hmac(JSONMessage, KeyId, ClientHMAC) of
                                              true ->
                                                  p_submit_payload(Token, Payload);
                                              false ->
                                                  #{<<"status">> => <<"error">>,
                                                    <<"reason">> => <<"invalid_hmac">>}
                                    end,
                                    {200, Rep, Req1};
                                _ ->
                                    {400, #{}, Req0}
                            end,
    ReqF = cowboy_req:reply(Status,
                            #{<<"content-type">> => <<"application/json">>},
                            jsx:encode(Reply),
                            Req2),

    cvmfs_fe_util:tock(<<"payload_not_shown">>, T0, micro_seconds),
    {ok, ReqF, State}.


%% Private functions


p_submit_payload(Token, Payload) ->
    case cvmfs_be:submit_payload(Token, Payload) of
        {ok, payload_added} ->
            #{<<"status">> => <<"ok">>};
        {error, Reason} ->
            #{<<"status">> => <<"error">>, <<"reason">> => atom_to_binary(Reason, latin1)}
    end.


{'fraction_non_alphanumeric': 0.25627101111973105, 'fraction_numerical': 0.00982673907421774, 'mean_word_length': 1.312406576980568, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 123, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5009509', 'n_tokens_mistral': 2061, 'n_tokens_neox': 1997, 'n_words': 516}