diff --git a/backend/src/uxbox/http.clj b/backend/src/uxbox/http.clj index 56401e141..0f24dee2b 100644 --- a/backend/src/uxbox/http.clj +++ b/backend/src/uxbox/http.clj @@ -12,7 +12,7 @@ [uxbox.core :refer [system]] [uxbox.config :as cfg] [uxbox.http.errors :as errors] - [uxbox.http.interceptors :as interceptors] + [uxbox.http.middleware :as middleware] [uxbox.http.session :as session] [uxbox.http.handlers :as handlers] [uxbox.http.debug :as debug] @@ -20,7 +20,7 @@ [vertx.core :as vc] [vertx.http :as vh] [vertx.web :as vw] - [vertx.web.interceptors :as vxi])) + [vertx.web.middleware :as vwm])) (defn- on-start [ctx] @@ -30,30 +30,32 @@ :allow-methods #{:post :get :patch :head :options :put} :allow-headers #{:x-requested-with :content-type :cookie}} - interceptors [(vxi/cookies) - (vxi/params) - (vxi/cors cors-opts) - interceptors/parse-request-body - interceptors/format-response-body - (vxi/errors errors/handle)] + routes [["/sub/:file-id" {:middleware [[vwm/cookies] + [vwm/cors cors-opts] + [middleware/format-response-body] + [session/auth]] + :handler ws/handler + :method :get}] - routes [["/sub/:file-id" {:interceptors [(vxi/cookies) - (vxi/cors cors-opts) - interceptors/format-response-body - (session/auth)] - :get ws/handler}] + ["/api" {:middleware [[vwm/cookies] + [vwm/params] + [vwm/cors cors-opts] + [middleware/parse-request-body] + [middleware/format-response-body] + [middleware/method-match] + [vwm/errors errors/handle]]} + ["/echo" {:handler handlers/echo-handler}] - ["/api" {:interceptors interceptors} - ["/echo" {:all handlers/echo-handler}] - ["/login" {:post handlers/login-handler}] - ["/logout" {:post handlers/logout-handler}] - ["/debug" - ["/emails" {:get debug/emails-list}] - ["/emails/:id" {:get debug/email}]] - ["/w" {:interceptors [(session/auth)]} - ["/mutation/:type" {:interceptors [(vxi/uploads)] - :post handlers/mutation-handler}] - ["/query/:type" {:get handlers/query-handler}]]]] + ["/login" {:handler handlers/login-handler + :method :post}] + ["/logout" {:handler handlers/logout-handler + :method :post}] + ["/w" {:middleware [session/auth]} + ["/mutation/:type" {:middleware [vwm/uploads] + :handler handlers/mutation-handler + :method :post}] + ["/query/:type" {:handler handlers/query-handler + :method :get}]]]] handler (vw/handler ctx (vw/assets "/media/*" {:root "resources/public/media/"}) diff --git a/backend/src/uxbox/http/handlers.clj b/backend/src/uxbox/http/handlers.clj index e4efe4b7f..ec99762f5 100644 --- a/backend/src/uxbox/http/handlers.clj +++ b/backend/src/uxbox/http/handlers.clj @@ -7,6 +7,7 @@ (ns uxbox.http.handlers (:require [promesa.core :as p] + [uxbox.common.exceptions :as ex] [uxbox.emails :as emails] [uxbox.http.session :as session] [uxbox.services.init] diff --git a/backend/src/uxbox/http/interceptors.clj b/backend/src/uxbox/http/interceptors.clj deleted file mode 100644 index 742606d2a..000000000 --- a/backend/src/uxbox/http/interceptors.clj +++ /dev/null @@ -1,72 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; This Source Code Form is "Incompatible With Secondary Licenses", as -;; defined by the Mozilla Public License, v. 2.0. -;; -;; Copyright (c) 2019-2020 Andrey Antukh - -(ns uxbox.http.interceptors - (:require - [vertx.web :as vw] - [uxbox.config :as cfg] - [uxbox.common.exceptions :as ex] - [uxbox.util.transit :as t]) - (:import - io.vertx.ext.web.RoutingContext - io.vertx.ext.web.FileUpload - io.vertx.core.buffer.Buffer)) - -(def parse-request-body - {:enter (fn [{:keys [request] :as data}] - (let [body (:body request) - mtype (get-in request [:headers "content-type"])] - (if (= "application/transit+json" mtype) - (try - (let [params (t/decode (t/buffer->bytes body))] - (update data :request assoc :body-params params)) - (catch Exception e - (ex/raise :type :parse - :message "Unable to parse transit from request body." - :cause e))) - data)))}) - -(def format-response-body - {:leave (fn [{:keys [response] :as data}] - (let [body (:body response) - type (if (:debug-humanize-transit cfg/config) - :json-verbose - :json)] - (cond - (coll? body) - (-> data - (assoc-in [:response :body] - (t/bytes->buffer (t/encode body {:type type}))) - (update-in [:response :headers] - assoc "content-type" "application/transit+json")) - - (nil? body) - (-> data - (assoc-in [:response :status] 204) - (assoc-in [:response :body] "")) - - :else - data)))}) - -(def handle-uploads - {:enter (fn [data] - (let [rcontext (get-in data [:request ::vw/routing-context]) - uploads (.fileUploads ^RoutingContext rcontext) - uploads (reduce (fn [acc ^FileUpload upload] - (assoc acc - (keyword (.name upload)) - {:type :uploaded-file - :mtype (.contentType upload) - :path (.uploadedFileName upload) - :name (.fileName upload) - :size (.size upload)})) - {} - uploads)] - (assoc-in data [:request :upload-params] uploads)))}) - diff --git a/backend/src/uxbox/http/middleware.clj b/backend/src/uxbox/http/middleware.clj new file mode 100644 index 000000000..877568f8c --- /dev/null +++ b/backend/src/uxbox/http/middleware.clj @@ -0,0 +1,85 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2019-2020 Andrey Antukh + +(ns uxbox.http.middleware + (:require + [promesa.core :as p] + [vertx.web :as vw] + [uxbox.config :as cfg] + [uxbox.common.exceptions :as ex] + [uxbox.util.transit :as t]) + (:import + io.vertx.ext.web.RoutingContext + io.vertx.ext.web.FileUpload + io.vertx.core.buffer.Buffer)) + +(defn- wrap-parse-request-body + [handler] + (fn [{:keys [headers body] :as request}] + (let [mtype (get headers "content-type")] + (if (= "application/transit+json" mtype) + (try + (let [params (t/decode (t/buffer->bytes body))] + (handler (assoc request :body-params params))) + (catch Exception e + (ex/raise :type :parse + :message "Unable to parse transit from request body." + :cause e))) + (handler request))))) + +(def parse-request-body + {:name ::parse-request-body + :compile (constantly wrap-parse-request-body)}) + +(defn- impl-format-response-body + [response] + (let [body (:body response) + type (if (:debug-humanize-transit cfg/config) + :json-verbose + :json)] + (cond + (coll? body) + (-> response + (assoc :body (t/bytes->buffer (t/encode body {:type type}))) + (update :headers assoc + "content-type" + "application/transit+json")) + + (nil? body) + (assoc response :status 204 :body "") + + :else + response))) + +(defn- wrap-format-response-body + [handler] + (fn [request] + (-> (p/do! (handler request)) + (p/then' (fn [response] + (cond-> response + (map? response) (impl-format-response-body))))))) + +(def format-response-body + {:name ::format-response-body + :compile (constantly wrap-format-response-body)}) + + +(defn- wrap-method-match + [handler] + (fn [request])) + +(def method-match + {:name ::method-match + :compile (fn [data opts] + (when-let [method (:method data)] + (fn [handler] + (fn [request] + (if (= (:method request) method) + (handler request) + {:status 405 :body ""})))))}) diff --git a/backend/src/uxbox/http/session.clj b/backend/src/uxbox/http/session.clj index 5394b65e2..75f8ed79b 100644 --- a/backend/src/uxbox/http/session.clj +++ b/backend/src/uxbox/http/session.clj @@ -7,7 +7,6 @@ (ns uxbox.http.session (:require [promesa.core :as p] - [sieppari.context :as spx] [vertx.core :as vc] [uxbox.db :as db] [uxbox.util.uuid :as uuid])) @@ -45,12 +44,16 @@ (catch java.lang.IllegalArgumentException e nil))) -(defn auth - [] - {:enter (fn [data] - (let [token (parse-token (:request data))] - (-> (retrieve token) - (p/then' (fn [user-id] - (if user-id - (update data :request assoc :user user-id) - data))))))}) +(defn- wrap-auth + [handler] + (fn [request] + (let [token (parse-token request)] + (-> (retrieve token) + (p/then (fn [profile-id] + (if profile-id + (handler (assoc request :profile-id profile-id)) + (handler request)))))))) + +(def auth + {:nane ::auth + :compile (constantly wrap-auth)})