From 3f34aa92fa46f7d785ff176e305c972f9a25e7be Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 5 Sep 2024 15:28:24 +0200 Subject: [PATCH] :sparkles: Add support for optional human challenge --- .../resources/templates/challenge.mustache | 18 ++++++++++++++++++ frontend/scripts/_helpers.js | 7 +++++++ frontend/src/app/main/data/users.cljs | 13 ++++++++++++- frontend/src/app/main/repo.cljs | 10 +++++++++- frontend/src/app/util/router.cljs | 16 ++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 frontend/resources/templates/challenge.mustache diff --git a/frontend/resources/templates/challenge.mustache b/frontend/resources/templates/challenge.mustache new file mode 100644 index 000000000..16bba9b6a --- /dev/null +++ b/frontend/resources/templates/challenge.mustache @@ -0,0 +1,18 @@ + + + + + Penpot - Challenge + + + + + + + diff --git a/frontend/scripts/_helpers.js b/frontend/scripts/_helpers.js index 0e284111d..6e2bd2765 100644 --- a/frontend/scripts/_helpers.js +++ b/frontend/scripts/_helpers.js @@ -333,6 +333,13 @@ async function generateTemplates() { await fs.writeFile("./resources/public/index.html", content); + content = await renderTemplate( + "resources/templates/challenge.mustache", + {}, + partials, + ); + await fs.writeFile("./resources/public/challenge.html", content); + content = await renderTemplate("resources/templates/preview-body.mustache", { manifest: manifest, translations: JSON.stringify(translations), diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index 375119931..bd27cddb8 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -137,13 +137,24 @@ (when (not= previous-email email) (set-current-team! nil))))))) +(defn- on-fetch-profile-exception + [cause] + (let [data (ex-data cause)] + (if (and (= :authorization (:type data)) + (= :challenge-required (:code data))) + (let [path (rt/get-current-path) + href (str "/challenge.html?redirect=" path)] + (rx/of (rt/nav-raw href))) + (rx/throw cause)))) + (defn fetch-profile [] (ptk/reify ::fetch-profile ptk/WatchEvent (watch [_ _ _] (->> (rp/cmd! :get-profile) - (rx/map profile-fetched))))) + (rx/map profile-fetched) + (rx/catch on-fetch-profile-exception))))) ;; --- EVENT: login diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index b19edf933..77d4de012 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -17,7 +17,7 @@ [cuerdas.core :as str])) (defn handle-response - [{:keys [status body] :as response}] + [{:keys [status body headers] :as response}] (cond (= 204 status) ;; We need to send "something" so the streams listening downstream can act @@ -40,6 +40,13 @@ {:type :validation :code :request-body-too-large})) + (and (= status 403) + (or (= "cloudflare" (get headers "server")) + (= "challenge" (get headers "cf-mitigated")))) + (rx/throw (ex-info "http error" + {:type :authorization + :code :challenge-required})) + (and (>= status 400) (map? body)) (rx/throw (ex-info "http error" body)) @@ -48,6 +55,7 @@ (ex-info "http error" {:type :unexpected-error :status status + :headers headers :data body})))) (def default-options diff --git a/frontend/src/app/util/router.cljs b/frontend/src/app/util/router.cljs index c4d541cfd..cb17f1a80 100644 --- a/frontend/src/app/util/router.cljs +++ b/frontend/src/app/util/router.cljs @@ -13,8 +13,10 @@ [app.main.data.events :as ev] [app.util.browser-history :as bhistory] [app.util.dom :as dom] + [app.util.globals :as globals] [app.util.timers :as ts] [beicon.v2.core :as rx] + [cuerdas.core :as str] [goog.events :as e] [potok.v2.core :as ptk] [reitit.core :as r])) @@ -143,6 +145,20 @@ (= (.-hostname location) (:host referrer))) (nav-back)))) +(defn nav-raw + [href] + (ptk/reify ::nav-raw + ptk/EffectEvent + (effect [_ _ _] + (set! (.-href globals/location) href)))) + +(defn get-current-path + [] + (let [hash (.-hash globals/location)] + (if (str/starts-with? hash "#") + (subs hash 1) + hash))) + ;; --- History API (defn initialize-history