diff --git a/backend/src/app/config.clj b/backend/src/app/config.clj index ad121323c..8dc9e49c5 100644 --- a/backend/src/app/config.clj +++ b/backend/src/app/config.clj @@ -268,10 +268,17 @@ ::telemetry-with-taiga ::tenant])) +(def default-flags + [:enable-backend-asserts + :enable-backend-api-doc + :enable-insecure-register + :enable-secure-session-cookies]) + (defn- parse-flags [config] - (-> (:flags config) - (flags/parse flags/default))) + (flags/parse flags/default + default-flags + (:flags config))) (defn read-env [prefix] diff --git a/backend/src/app/http/doc.clj b/backend/src/app/http/doc.clj index 13a6075cc..29796a117 100644 --- a/backend/src/app/http/doc.clj +++ b/backend/src/app/http/doc.clj @@ -45,7 +45,7 @@ (defn handler [rpc] (let [context (prepare-context rpc)] - (if (contains? cf/flags :api-doc) + (if (contains? cf/flags :backend-api-doc) (fn [_] {:status 200 :body (-> (io/resource "api-doc.tmpl") diff --git a/backend/src/app/http/oauth.clj b/backend/src/app/http/oauth.clj index 64b1c7036..faa2c247e 100644 --- a/backend/src/app/http/oauth.clj +++ b/backend/src/app/http/oauth.clj @@ -203,6 +203,7 @@ (sxf request))) (let [info (assoc info :iss :prepared-register + :is-active true :exp (dt/in-future {:hours 48})) token (tokens :generate info) params (d/without-nils diff --git a/backend/src/app/http/session.clj b/backend/src/app/http/session.clj index 6b9a566fd..462e86c62 100644 --- a/backend/src/app/http/session.clj +++ b/backend/src/app/http/session.clj @@ -53,12 +53,13 @@ (defn- add-cookies [response {:keys [id] :as session}] - (let [cors? (contains? cfg/flags :cors)] + (let [cors? (contains? cfg/flags :cors) + secure? (contains? cfg/flags :secure-session-cookies)] (assoc response :cookies {cookie-name {:path "/" :http-only true :value id :same-site (if cors? :none :strict) - :secure true}}))) + :secure secure?}}))) (defn- clear-cookies [response] diff --git a/backend/src/app/rpc/mutations/demo.clj b/backend/src/app/rpc/mutations/demo.clj index cca26dbb4..abf652f03 100644 --- a/backend/src/app/rpc/mutations/demo.clj +++ b/backend/src/app/rpc/mutations/demo.clj @@ -34,7 +34,7 @@ params {:id id :email email :fullname fullname - :is-demo true + :is-active true :deleted-at (dt/in-future cf/deletion-delay) :password password :props {:onboarding-viewed true}}] diff --git a/backend/src/app/rpc/mutations/profile.clj b/backend/src/app/rpc/mutations/profile.clj index 3598fea73..45c2bb5bd 100644 --- a/backend/src/app/rpc/mutations/profile.clj +++ b/backend/src/app/rpc/mutations/profile.clj @@ -124,9 +124,7 @@ ;; --- MUTATION: Register Profile -(s/def ::accept-terms-and-privacy ::us/boolean) (s/def ::token ::us/not-empty-string) - (s/def ::register-profile (s/keys :req-un [::token ::fullname])) @@ -146,13 +144,17 @@ (defn register-profile [{:keys [conn tokens session metrics] :as cfg} {:keys [token] :as params}] - (let [claims (tokens :verify {:token token :iss :prepared-register}) - params (merge params claims)] + (let [claims (tokens :verify {:token token :iss :prepared-register}) + params (merge params claims)] + (check-profile-existence! conn params) - (let [profile (->> params - (create-profile conn) - (create-profile-relations conn) - (decode-profile-row))] + + (let [is-active (or (:is-active params) + (contains? cf/flags :insecure-register)) + profile (->> (assoc params :is-active is-active) + (create-profile conn) + (create-profile-relations conn) + (decode-profile-row))] (cond ;; If invitation token comes in params, this is because the ;; user comes from team-invitation process; in this case, @@ -182,6 +184,15 @@ ::audit/props (audit/profile->props profile) ::audit/profile-id (:id profile)}) + ;; If the `:enable-insecure-register` flag is set, we proceed + ;; to sign in the user directly, without email verification. + (true? is-active) + (with-meta (profile/strip-private-attrs profile) + {:transform-response ((:create session) (:id profile)) + :before-complete (annotate-profile-register metrics) + ::audit/props (audit/profile->props profile) + ::audit/profile-id (:id profile)}) + ;; In all other cases, send a verification email. :else (let [vtoken (tokens :generate @@ -226,7 +237,7 @@ backend (:backend params "penpot") is-demo (:is-demo params false) is-muted (:is-muted params false) - is-active (:is-active params (or (not= "penpot" backend) is-demo)) + is-active (:is-active params false) email (str/lower (:email params)) params {:id id diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index acc1d2c5c..149f71c65 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -10,30 +10,28 @@ [cuerdas.core :as str])) (def default - #{:backend-asserts - :api-doc - :registration - :demo-users}) + "A common flags that affects both: backend and frontend." + [:enable-registration + :enable-demo-users]) (defn parse - ([flags] (parse flags #{})) - ([flags default] - (loop [flags (seq flags) - result default] - (let [item (first flags)] - (if (nil? item) - result - (let [sname (name item)] - (cond - (str/starts-with? sname "enable-") - (recur (rest flags) - (conj result (keyword (subs sname 7)))) + [& flags] + (loop [flags (apply concat flags) + result #{}] + (let [item (first flags)] + (if (nil? item) + result + (let [sname (name item)] + (cond + (str/starts-with? sname "enable-") + (recur (rest flags) + (conj result (keyword (subs sname 7)))) - (str/starts-with? sname "disable-") - (recur (rest flags) - (disj result (keyword (subs sname 8)))) + (str/starts-with? sname "disable-") + (recur (rest flags) + (disj result (keyword (subs sname 8)))) - :else - (recur (rest flags) result)))))))) + :else + (recur (rest flags) result))))))) diff --git a/docker/devenv/docker-compose.yaml b/docker/devenv/docker-compose.yaml index 764b638db..e073eb2ce 100644 --- a/docker/devenv/docker-compose.yaml +++ b/docker/devenv/docker-compose.yaml @@ -50,7 +50,7 @@ services: - PENPOT_SMTP_PASSWORD= - PENPOT_SMTP_SSL=false - PENPOT_SMTP_TLS=false - - PENPOT_FLAGS="enable-cors" + - PENPOT_FLAGS="enable-cors enable-insecure-register enable-terms-and-privacy-checkbox" # LDAP setup - PENPOT_LDAP_HOST=ldap diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 9e308a1ca..3dbe3e127 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -57,8 +57,8 @@ (defn- parse-flags [global] (let [flags (obj/get global "penpotFlags" "") - flags (into #{} (map keyword) (str/words flags))] - (flags/parse flags flags/default))) + flags (sequence (map keyword) (str/words flags))] + (flags/parse flags/default flags))) (defn- parse-version [global] diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index 71cc32eeb..84c362fb2 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -169,7 +169,9 @@ (let [token (:invitation-token data)] (st/emit! (rt/nav :auth-verify-token {} {:token token}))) - (not= "penpot" (:auth-backend data)) + ;; The :is-active flag is true, when insecure-register is enabled + ;; or the user used external auth provider. + (:is-active data) (st/emit! (du/login-from-register)) :else @@ -178,9 +180,14 @@ (s/def ::accept-terms-and-privacy (s/and ::us/boolean true?)) (s/def ::accept-newsletter-subscription ::us/boolean) -(s/def ::register-validate-form - (s/keys :req-un [::token ::fullname ::accept-terms-and-privacy] - :opt-un [::accept-newsletter-subscription])) +(if (contains? @cf/flags :terms-and-privacy-checkbox) + (s/def ::register-validate-form + (s/keys :req-un [::token ::fullname ::accept-terms-and-privacy] + :opt-un [::accept-newsletter-subscription])) + (s/def ::register-validate-form + (s/keys :req-un [::token ::fullname] + :opt-un [::accept-terms-and-privacy + ::accept-newsletter-subscription]))) (mf/defc register-validate-form [{:keys [params] :as props}] @@ -207,23 +214,17 @@ :label (tr "auth.fullname") :type "text"}]] - [:div.fields-row - [:& fm/input {:name :accept-terms-and-privacy - :class "check-primary" - :type "checkbox"} - [:span - (tr "auth.terms-privacy-agreement") - [:div - [:a {:href "https://penpot.app/terms.html" :target "_blank"} (tr "auth.terms-of-service")] - [:span ",\u00A0"] - [:a {:href "https://penpot.app/privacy.html" :target "_blank"} (tr "auth.privacy-policy")]]]]] - - ;; (when (contains? @cf/flags :newsletter-registration-check) - ;; [:div.fields-row - ;; [:& fm/input {:name :accept-newsletter-subscription - ;; :class "check-primary" - ;; :label (tr "auth.newsletter-subscription") - ;; :type "checkbox"}]]) + (when (contains? @cf/flags :terms-and-privacy-checkbox) + [:div.fields-row + [:& fm/input {:name :accept-terms-and-privacy + :class "check-primary" + :type "checkbox"} + [:span + (tr "auth.terms-privacy-agreement") + [:div + [:a {:href "https://penpot.app/terms.html" :target "_blank"} (tr "auth.terms-of-service")] + [:span ",\u00A0"] + [:a {:href "https://penpot.app/privacy.html" :target "_blank"} (tr "auth.privacy-policy")]]]]]) [:& fm/submit-button {:label (tr "auth.register-submit")