diff --git a/.gitignore b/.gitignore index 783eda0c1..da0baf3e6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ node_modules /backend/dist/ /backend/- /backend/.rebel_readline_history +/frontend/.rebel_readline_history /frontend/.cpcache /frontend/npm-debug.log /frontend/target/ diff --git a/backend/src/uxbox/http/cors.clj b/backend/src/uxbox/http/cors.clj new file mode 100644 index 000000000..06133c085 --- /dev/null +++ b/backend/src/uxbox/http/cors.clj @@ -0,0 +1,78 @@ +;; 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/. +;; +;; Copyright (c) 2019 Andrey Antukh + +(ns uxbox.http.cors + "CORS Implementation for Async Ring" + (:require [cuerdas.core :as str])) + +(defn- allow-origin? + [value {:keys [origin]}] + (prn "allow-origin?" value origin) + (cond + (nil? value) value + (= origin "*") origin + (set? origin) (origin value) + (= origin value) origin)) + +(defn- normalize-headers + [headers] + (->> (map (comp str/lower name) headers) + (str/join ","))) + +(defn- normalize-methods + [methods] + (->> (map (comp str/upper name) methods) + (str/join ","))) + +(defn- get-preflight-headers + [origin {:keys [allow-methods allow-headers max-age allow-credentials] + :or {allow-methods #{:get :post :put :delete}} + :as opts}] + (when-let [origin (allow-origin? origin opts)] + (cond-> {"access-control-allow-origin" origin + "access-control-allow-methods" (normalize-methods allow-methods)} + allow-credentials + (assoc "access-control-allow-credentials" "true") + + max-age + (assoc "access-control-max-age" (str max-age)) + + allow-headers + (assoc "access-control-allow-headers" (normalize-headers allow-headers))))) + +(defn get-response-headers + [origin {:keys [allow-headers expose-headers allow-credentials] :as opts}] + (when-let [origin (allow-origin? origin opts)] + (cond-> {"access-control-allow-origin" origin} + allow-credentials + (assoc "access-control-allow-credentials" "true") + + allow-headers + (assoc "access-control-allow-headers" (normalize-headers allow-headers)) + + expose-headers + (assoc "access-control-expose-headers" (normalize-headers expose-headers))))) + +(defn- cors-preflight? + [{:keys [request-method headers] :as req}] + (and (= request-method :options) + (contains? headers "origin") + (contains? headers "access-control-request-method"))) + +(defn wrap-cors + "A chain handler that handles cors related headers." + [handler opts] + (fn [{:keys [headers] :as req} respond raise] + (let [origin (get headers "origin")] + (if (cors-preflight? req) + (let [headers (get-preflight-headers origin opts)] + (respond {:status 200 :headers headers :body ""})) + (let [headers (get-response-headers origin opts) + wrapped-respond (fn [response] (respond (update response :headers merge headers)))] + (handler req wrapped-respond raise)))))) + + + diff --git a/backend/src/uxbox/http/middleware.clj b/backend/src/uxbox/http/middleware.clj index 24c86e6d4..e343602b1 100644 --- a/backend/src/uxbox/http/middleware.clj +++ b/backend/src/uxbox/http/middleware.clj @@ -19,6 +19,7 @@ [ring.middleware.session :refer [wrap-session]] [ring.middleware.session.cookie :refer [cookie-store]] [ring.middleware.multipart-params :refer [wrap-multipart-params]] + [uxbox.http.cors :refer [wrap-cors]] [uxbox.http.errors :as errors] [uxbox.http.response :as rsp] [uxbox.util.data :refer [normalize-attrs]] @@ -107,10 +108,22 @@ (def ^:private session-middleware (let [options {:store (cookie-store {:key "a 16-byte secret"}) :cookie-name "session" - :cookie-attrs {:same-site :lax :http-only true}}] + :cookie-attrs {:same-site :lax + :http-only false}}] {:name ::session-middleware :wrap #(wrap-session % options)})) +(def cors-conf + {:origin #{"http://127.0.0.1:3449"} + :max-age 3600 + :allow-credentials true + :allow-methods #{:post :put :get :delete} + :allow-headers #{:x-requested-with :content-type :cookie}}) + +(def ^:private cors-middleware + {:name ::cors-middleware + :wrap #(wrap-cors % cors-conf)}) + ;; (def ^:private cors-middleware ;; {:name ::cors-middleware ;; :wrap #(wrap-cors % @@ -152,7 +165,8 @@ (respond (rsp/forbidden nil))))))}) (def middleware - [session-middleware + [cors-middleware + session-middleware parameters/parameters-middleware muuntaja/format-negotiate-middleware ;; encoding response body