diff --git a/backend/src/app/http/oauth.clj b/backend/src/app/http/oauth.clj index 63b9f481d..41a40ab18 100644 --- a/backend/src/app/http/oauth.clj +++ b/backend/src/app/http/oauth.clj @@ -6,7 +6,6 @@ (ns app.http.oauth (:require - [app.common.data :as d] [app.common.exceptions :as ex] [app.common.spec :as us] [app.common.uri :as u] @@ -99,10 +98,11 @@ res (http/send! req)] (when (= 200 (:status res)) - (let [{:keys [name] :as data} (json/read-str (:body res) :key-fn keyword)] - (-> data - (assoc :backend (:name provider)) - (assoc :fullname name))))) + (let [info (json/read-str (:body res) :key-fn keyword)] + {:backend (:name provider) + :email (:email info) + :fullname (:name info) + :props (dissoc info :name :email)}))) (catch Exception e (l/error :hint "unexpected exception on retrieve-user-info" @@ -118,7 +118,8 @@ (retrieve-user-info cfg))] (when-not info (ex/raise :type :internal - :code :unable-to-auth)) + :code :unable-to-auth + :hint "no user info")) ;; If the provider is OIDC, we can proceed to check ;; roles if they are defined. @@ -141,8 +142,10 @@ (some? (:invitation-token state)) (assoc :invitation-token (:invitation-token state)) + ;; If state token comes with props, merge them. The state token + ;; props can contain pm_ and utm_ prefixed query params. (map? (:props state)) - (d/merge (:props state))))) + (update :props merge (:props state))))) ;; --- HTTP HANDLERS @@ -152,7 +155,8 @@ (let [sk (name k)] (cond-> params (or (str/starts-with? sk "pm_") - (str/starts-with? sk "pm-")) + (str/starts-with? sk "pm-") + (str/starts-with? sk "utm_")) (assoc (-> sk str/kebab keyword) v)))) {} params)) @@ -254,9 +258,7 @@ [cfg] (let [opts {:client-id (cf/get :google-client-id) :client-secret (cf/get :google-client-secret) - :scopes #{"email" "profile" "openid" - "https://www.googleapis.com/auth/userinfo.email" - "https://www.googleapis.com/auth/userinfo.profile"} + :scopes #{"openid" "email" "profile"} :auth-uri "https://accounts.google.com/o/oauth2/v2/auth" :token-uri "https://oauth2.googleapis.com/token" :user-uri "https://openidconnect.googleapis.com/v1/userinfo" @@ -272,8 +274,7 @@ [cfg] (let [opts {:client-id (cf/get :github-client-id) :client-secret (cf/get :github-client-secret) - :scopes #{"read:user" - "user:email"} + :scopes #{"read:user" "user:email"} :auth-uri "https://github.com/login/oauth/authorize" :token-uri "https://github.com/login/oauth/access_token" :user-uri "https://api.github.com/user" diff --git a/backend/src/app/loggers/audit.clj b/backend/src/app/loggers/audit.clj index 7d8c7e583..7513f9825 100644 --- a/backend/src/app/loggers/audit.clj +++ b/backend/src/app/loggers/audit.clj @@ -24,19 +24,33 @@ [lambdaisland.uri :as u])) (defn clean-props - "Cleans the params from complex data, only accept strings, numbers and - uuids and removing sensitive data such as :password and related - props." - [params] - (let [params (dissoc params :session-id :password :old-password :token)] - (reduce-kv (fn [params k v] - (cond-> params - (or (string? v) - (uuid? v) - (number? v)) - (assoc k v))) - {} - params))) + [{:keys [profile-id] :as event}] + (letfn [(clean-common [props] + (-> props + (dissoc :session-id) + (dissoc :password) + (dissoc :old-password) + (dissoc :token))) + + (clean-profile-id [props] + (cond-> props + (= profile-id (:profile-id props)) + (dissoc :profile-id))) + + (clean-complex-data [props] + (reduce-kv (fn [props k v] + (cond-> props + (or (string? v) + (uuid? v) + (boolean? v) + (number? v)) + (assoc k v) + + (keyword? v) + (assoc k (name v)))) + {} + props))] + (update event :props #(-> % clean-common clean-profile-id clean-complex-data)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Collector @@ -52,11 +66,16 @@ (defmethod ig/pre-init-spec ::collector [_] (s/keys :req-un [::db/pool ::wrk/executor ::enabled])) +(def event-xform + (comp + (filter :profile-id) + (map clean-props))) + (defmethod ig/init-key ::collector [_ {:keys [enabled] :as cfg}] (when enabled (l/info :msg "intializing audit collector") - (let [input (a/chan) + (let [input (a/chan 1 event-xform) buffer (aa/batch input {:max-batch-size 100 :max-batch-age (* 5 1000) :init []})] @@ -65,14 +84,17 @@ (l/debug :action "persist-events (batch)" :reason (name type) :count (count events)) - (a/ (assoc cfg :conn conn) - (login-or-register params))] + (login-or-register params)) + props (merge + (select-keys profile [:backend :fullname :email]) + (:props profile))] (with-meta profile - {:before-complete (annotate-profile-register metrics profile)})))) + {:before-complete (annotate-profile-register metrics profile) + ::audit/name (if (::created profile) "register" "login") + ::audit/props props + ::audit/profile-id (:id profile)})))) (defn login-or-register - [{:keys [conn] :as cfg} {:keys [email backend] :as params}] - (letfn [(info->props [info] - (dissoc info :name :fullname :email :backend)) - - (info->lang [{:keys [locale] :as info}] + [{:keys [conn] :as cfg} {:keys [email] :as params}] + (letfn [(info->lang [{:keys [locale] :as info}] (when (and (string? locale) (not (str/blank? locale))) locale)) - (create-profile [conn {:keys [email] :as info}] - (db/insert! conn :profile - {:id (uuid/next) - :fullname (:fullname info) - :email (str/lower email) - :lang (info->lang info) - :auth-backend backend - :is-active true - :password "!" - :props (db/tjson (info->props info)) - :is-demo false})) + (create-profile [conn {:keys [fullname backend email props] :as info}] + (let [params {:id (uuid/next) + :fullname fullname + :email (str/lower email) + :lang (info->lang props) + :auth-backend backend + :is-active true + :password "!" + :props (db/tjson props) + :is-demo false}] + (-> (db/insert! conn :profile params) + (update :props db/decode-transit-pgobject)))) (update-profile [conn info profile] - (let [props (d/merge (:props profile) - (info->props info))] + (let [props (merge (:props profile) + (:props info))] (db/update! conn :profile {:props (db/tjson props) :modified-at (dt/now)} @@ -614,7 +619,7 @@ ;; Schedule a complete deletion of profile (wrk/submit! {::wrk/task :delete-profile - ::wrk/dalay cfg/deletion-delay + ::wrk/delay cfg/deletion-delay ::wrk/conn conn :profile-id profile-id}) diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index 73142e4ae..906df6b8d 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -379,9 +379,11 @@ on-success identity}} (meta params)] (->> (rp/mutation :delete-profile {}) (rx/tap on-success) + (rx/delay-at-least 300) + (rx/catch (constantly (rx/of 1))) + (rx/map logged-out) (rx/catch on-error)))))) - ;; --- EVENT: request-profile-recovery (s/def ::request-profile-recovery diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index fe3ef3c59..f26881ddb 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -12,7 +12,7 @@ [app.main.store :as st] [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] - [app.util.i18n :as i18n :refer [tr t]] + [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] @@ -25,42 +25,36 @@ (rx/of (dm/error msg))) (rx/throw error))) -(defn on-success - [x] - (st/emit! (rt/nav :auth-login))) - (mf/defc delete-account-modal {::mf/register modal/components ::mf/register-as :delete-account} [props] - (let [locale (mf/deref i18n/locale) - on-close + (let [on-close (mf/use-callback (st/emitf (modal/hide))) on-accept (mf/use-callback (st/emitf (modal/hide) (du/request-account-deletion - (with-meta {} {:on-error on-error - :on-success on-success}))))] + (with-meta {} {:on-error on-error}))))] [:div.modal-overlay [:div.modal-container.change-email-modal [:div.modal-header [:div.modal-header-title - [:h2 (t locale "modals.delete-account.title")]] + [:h2 (tr "modals.delete-account.title")]] [:div.modal-close-button {:on-click on-close} i/close]] [:div.modal-content [:& msgs/inline-banner {:type :warning - :content (t locale "modals.delete-account.info")}]] + :content (tr "modals.delete-account.info")}]] [:div.modal-footer [:div.action-buttons [:button.btn-warning.btn-large {:on-click on-accept} - (t locale "modals.delete-account.confirm")] + (tr "modals.delete-account.confirm")] [:button.btn-secondary.btn-large {:on-click on-close} - (t locale "modals.delete-account.cancel")]]]]])) + (tr "modals.delete-account.cancel")]]]]])) diff --git a/manage.sh b/manage.sh index 6ea162e26..80d9c6a85 100755 --- a/manage.sh +++ b/manage.sh @@ -98,6 +98,54 @@ Copyright (c) UXBOX Labs SL EOF } +function build-frontend-bundle { + echo ">> bundle frontend start"; + + local version=$(print-current-version); + local bundle_dir="./bundle-frontend"; + + build "frontend"; + + rm -rf $bundle_dir; + mv ./frontend/target/dist $bundle_dir; + echo $version > $bundle_dir/version.txt; + put-license-file $bundle_dir; + echo ">> bundle frontend end"; +} + +function build-backend-bundle { + echo ">> bundle backend start"; + + local version=$(print-current-version); + local bundle_dir="./bundle-backend"; + + build "backend"; + + rm -rf $bundle_dir; + mv ./backend/target/dist $bundle_dir; + echo $version > $bundle_dir/version.txt; + put-license-file $bundle_dir; + echo ">> bundle frontend end"; +} + +function build-exporter-bundle { + echo ">> bundle exporter start"; + local version=$(print-current-version); + local bundle_dir="./bundle-exporter"; + + build "exporter"; + + rm -rf $bundle_dir; + mv ./exporter/target $bundle_dir; + + echo $version > $bundle_dir/version.txt + put-license-file $bundle_dir; + + echo ">> bundle exporter end"; +} + +# DEPRECATED: temporary mantained for backward compatibilty. + function build-app-bundle { echo ">> bundle app start"; @@ -117,22 +165,6 @@ function build-app-bundle { echo ">> bundle app end"; } -function build-exporter-bundle { - echo ">> bundle exporter start"; - local version=$(print-current-version); - local bundle_dir="./bundle-exporter"; - - build "exporter"; - - rm -rf $bundle_dir; - mv ./exporter/target $bundle_dir; - - echo $version > $bundle_dir/version.txt - put-license-file $bundle_dir; - - echo ">> bundle exporter end"; -} - function usage { echo "PENPOT build & release manager" echo "USAGE: $0 OPTION" @@ -182,6 +214,14 @@ case $1 in build-app-bundle; ;; + build-frontend-bundle) + build-frontend-bundle; + ;; + + build-backend-bundle) + build-backend-bundle; + ;; + build-exporter-bundle) build-exporter-bundle; ;;