% Copyright (c) 2025 Onomondo ApS & sysmocom - s.f.m.c. GmbH. All rights reserved. % % SPDX-License-Identifier: AGPL-3.0-only % % Author: Harald Welte / sysmocom - s.f.m.c. GmbH -module(rest_middleware). -behaviour(cowboy_middleware). -export([execute/2]). % Derive the X-ADMIN-PROTOCOL string from the URN contained in the $id field of the related JSON schema. protocol_from_json_schema(JsonSchemaName) -> JsonSchema = jesse_database:load(JsonSchemaName), {[{<<"$id">>, JsonSchemaId} | _]} = JsonSchema, JsonSchemaIdUrnPath = maps:get(path, uri_string:parse(JsonSchemaId)), [_, Protocol] = string:split(JsonSchemaIdUrnPath, ":"), Protocol. % Cowboy middleware callback, make sure that the X-ADMIN-PROTOCOL field contains the expected protocol % identifier for incoming POST requests. For outgoing requests, set the X-ADMIN-PROTOCOL. Both strings % are derived from the related JSON schema. execute(Req0 = #{method := <<"POST">>}, State) -> ExpectedProtocol = protocol_from_json_schema("rest_api_resource_schema"), case cowboy_req:header(<<"x-admin-protocol">>, Req0) of ExpectedProtocol -> {ok, Req0, State}; Protocol -> logger:error( "Rejecting incompatible REST request: ~s,~nProtocol=~p, Peer=~p, Pid=~p~n", [maps:get(path, Req0), Protocol, maps:get(peer, Req0), maps:get(pid, Req0)] ), Req = cowboy_req:reply(400, #{}, <<"Unsupported x-admin-protocol">>, Req0), {stop, Req} end; execute(Req0, Env) -> Protocol = protocol_from_json_schema("rest_api_response_schema"), Req1 = cowboy_req:set_resp_header(<<"x-admin-protocol">>, Protocol, Req0), {ok, Req1, Env}.