From 07b8a2a6e6c9e414e8923094297089937d33a747 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 5 Mar 2024 19:06:29 +0100 Subject: [PATCH] :sparkles: Restrict http methods on RPC handlers --- backend/src/app/http/errors.clj | 8 ++++++-- backend/src/app/rpc.clj | 36 ++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/backend/src/app/http/errors.clj b/backend/src/app/http/errors.clj index 580cd6703..18350d21d 100644 --- a/backend/src/app/http/errors.clj +++ b/backend/src/app/http/errors.clj @@ -60,8 +60,12 @@ (defmethod handle-error :restriction [err _ _] - {::rres/status 400 - ::rres/body (ex-data err)}) + (let [{:keys [code] :as data} (ex-data err)] + (if (= code :method-not-allowed) + {::rres/status 405 + ::rres/body data} + {::rres/status 400 + ::rres/body data}))) (defmethod handle-error :rate-limit [err _ _] diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 2f999a08e..8ae7a38d6 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -31,6 +31,7 @@ [app.util.services :as sv] [app.util.time :as dt] [clojure.spec.alpha :as s] + [cuerdas.core :as str] [integrant.core :as ig] [promesa.core :as p] [ring.request :as rreq] @@ -71,24 +72,31 @@ (defn- rpc-handler "Ring handler that dispatches cmd requests and convert between internal async flow into ring async flow." - [methods {:keys [params path-params] :as request}] - (let [type (keyword (:type path-params)) - etag (rreq/get-header request "if-none-match") - profile-id (or (::session/profile-id request) - (::actoken/profile-id request)) + [methods {:keys [params path-params method] :as request}] + (let [handler-name (:type path-params) + etag (rreq/get-header request "if-none-match") + profile-id (or (::session/profile-id request) + (::actoken/profile-id request)) - data (-> params - (assoc ::request-at (dt/now)) - (assoc ::session/id (::session/id request)) - (assoc ::cond/key etag) - (cond-> (uuid? profile-id) - (assoc ::profile-id profile-id))) + data (-> params + (assoc ::request-at (dt/now)) + (assoc ::session/id (::session/id request)) + (assoc ::cond/key etag) + (cond-> (uuid? profile-id) + (assoc ::profile-id profile-id))) - data (vary-meta data assoc ::http/request request) - method (get methods type default-handler)] + data (vary-meta data assoc ::http/request request) + handler-fn (get methods (keyword handler-name) default-handler)] + + (when (and (or (= method :get) + (= method :head)) + (not (str/starts-with? handler-name "get-"))) + (ex/raise :type :restriction + :code :method-not-allowed + :hint "method not allowed for this request")) (binding [cond/*enabled* true] - (let [response (method data)] + (let [response (handler-fn data)] (handle-response request response))))) (defn- wrap-metrics