Merge pull request #616 from penpot/niwinz/bugfixes-1

Bugfixes
This commit is contained in:
Andrés Moya 2021-02-10 12:13:47 +01:00 committed by GitHub
commit 068a099f37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 138 additions and 81 deletions

View file

@ -31,8 +31,8 @@ in the changelog.**
## Pull requests ## ## Pull requests ##
If you want propose a change or bug fix with the Pull-Request system If you want propose a change or bug fix with the Pull-Request system
firstly you should carefully read the **Contributor License Aggreement** firstly you should carefully read the **DCO** section and format your
section and format your commits accordingly. commits accordingly.
If you intend to fix a bug it's fine to submit a pull request right If you intend to fix a bug it's fine to submit a pull request right
away but we still recommend to file an issue detailing what you're away but we still recommend to file an issue detailing what you're

View file

@ -57,7 +57,6 @@
:registration-domain-whitelist "" :registration-domain-whitelist ""
:telemetry-enabled false :telemetry-enabled false
:telemetry-with-taiga true
:telemetry-uri "https://telemetry.penpot.app/" :telemetry-uri "https://telemetry.penpot.app/"
;; LDAP auth disabled by default. Set ldap-auth-host to enable ;; LDAP auth disabled by default. Set ldap-auth-host to enable

View file

@ -72,7 +72,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def initsql (def initsql
(str "SET statement_timeout = 10000;\n" (str "SET statement_timeout = 60000;\n"
"SET idle_in_transaction_session_timeout = 120000;")) "SET idle_in_transaction_session_timeout = 120000;"))
(defn- create-datasource-config (defn- create-datasource-config

View file

@ -35,51 +35,40 @@
(defn- get-access-token (defn- get-access-token
[cfg code] [cfg code]
(let [params {:code code (try
:client_id (:client-id cfg) (let [params {:code code
:client_secret (:client-secret cfg) :client_id (:client-id cfg)
:redirect_uri (build-redirect-url cfg) :client_secret (:client-secret cfg)
:grant_type "authorization_code"} :redirect_uri (build-redirect-url cfg)
req {:method :post :grant_type "authorization_code"}
:headers {"content-type" "application/x-www-form-urlencoded"} req {:method :post
:uri "https://oauth2.googleapis.com/token" :headers {"content-type" "application/x-www-form-urlencoded"}
:body (uri/map->query-string params)} :uri "https://oauth2.googleapis.com/token"
res (http/send! req)] :body (uri/map->query-string params)}
res (http/send! req)]
(when (not= 200 (:status res)) (when (= 200 (:status res))
(ex/raise :type :internal (-> (json/read-str (:body res))
:code :invalid-response-from-google (get "access_token"))))
:context {:status (:status res)
:body (:body res)}))
(try (catch Exception e
(let [data (json/read-str (:body res))] (log/error e "unexpected error on get-access-token")
(get data "access_token")) nil)))
(catch Throwable e
(log/error "unexpected error on parsing response body from google access token request" e)
nil))))
(defn- get-user-info (defn- get-user-info
[token] [token]
(let [req {:uri "https://openidconnect.googleapis.com/v1/userinfo" (try
:headers {"Authorization" (str "Bearer " token)} (let [req {:uri "https://openidconnect.googleapis.com/v1/userinfo"
:method :get} :headers {"Authorization" (str "Bearer " token)}
res (http/send! req)] :method :get}
res (http/send! req)]
(when (not= 200 (:status res)) (when (= 200 (:status res))
(ex/raise :type :internal (let [data (json/read-str (:body res))]
:code :invalid-response-from-google {:email (get data "email")
:context {:status (:status res) :fullname (get data "name")})))
:body (:body res)})) (catch Exception e
(log/error e "unexpected exception on get-user-info")
(try nil)))
(let [data (json/read-str (:body res))]
;; (clojure.pprint/pprint data)
{:email (get data "email")
:fullname (get data "name")})
(catch Throwable e
(log/error "unexpected error on parsing response body from google access token request" e)
nil))))
(defn- auth (defn- auth
[{:keys [tokens] :as cfg} _req] [{:keys [tokens] :as cfg} _req]
@ -99,33 +88,39 @@
(defn- callback (defn- callback
[{:keys [tokens rpc session] :as cfg} request] [{:keys [tokens rpc session] :as cfg} request]
(let [token (get-in request [:params :state]) (try
_ (tokens :verify {:token token :iss :google-oauth}) (let [token (get-in request [:params :state])
info (some->> (get-in request [:params :code]) _ (tokens :verify {:token token :iss :google-oauth})
(get-access-token cfg) info (some->> (get-in request [:params :code])
(get-user-info))] (get-access-token cfg)
(get-user-info))
(when-not info _ (when-not info
(ex/raise :type :authentication (ex/raise :type :internal
:code :unable-to-authenticate-with-google)) :code :unable-to-auth))
method-fn (get-in rpc [:methods :mutation :login-or-register])
(let [method-fn (get-in rpc [:methods :mutation :login-or-register])
profile (method-fn {:email (:email info) profile (method-fn {:email (:email info)
:fullname (:fullname info)}) :fullname (:fullname info)})
uagent (get-in request [:headers "user-agent"]) uagent (get-in request [:headers "user-agent"])
token (tokens :generate {:iss :auth token (tokens :generate {:iss :auth
:exp (dt/in-future "15m") :exp (dt/in-future "15m")
:profile-id (:id profile)}) :profile-id (:id profile)})
uri (-> (uri/uri (:public-uri cfg)) uri (-> (uri/uri (:public-uri cfg))
(assoc :path "/#/auth/verify-token") (assoc :path "/#/auth/verify-token")
(assoc :query (uri/map->query-string {:token token}))) (assoc :query (uri/map->query-string {:token token})))
sid (session/create! session {:profile-id (:id profile) sid (session/create! session {:profile-id (:id profile)
:user-agent uagent})] :user-agent uagent})]
{:status 302 {:status 302
:headers {"location" (str uri)} :headers {"location" (str uri)}
:cookies (session/cookies session {:value sid}) :cookies (session/cookies session {:value sid})
:body ""}))) :body ""})
(catch Exception _e
(let [uri (-> (uri/uri (:public-uri cfg))
(assoc :path "/#/auth/login")
(assoc :query (uri/map->query-string {:error "unable-to-auth"})))]
{:status 302
:headers {"location" (str uri)}
:body ""}))))
(s/def ::client-id ::us/not-empty-string) (s/def ::client-id ::us/not-empty-string)
(s/def ::client-secret ::us/not-empty-string) (s/def ::client-secret ::us/not-empty-string)

View file

@ -192,19 +192,19 @@
:fn (ig/ref :app.tasks.file-media-gc/handler)} :fn (ig/ref :app.tasks.file-media-gc/handler)}
{:id "file-xlog-gc" {:id "file-xlog-gc"
:cron #app/cron "0 0 */6 * * ?" ;; every 2 hours :cron #app/cron "0 0 */1 * * ?" ;; hourly
:fn (ig/ref :app.tasks.file-xlog-gc/handler)} :fn (ig/ref :app.tasks.file-xlog-gc/handler)}
{:id "storage-deleted-gc" {:id "storage-deleted-gc"
:cron #app/cron "0 0 */6 * * ?" ;; every 6 hours :cron #app/cron "0 0 1 */1 * ?" ;; daily (1 hour shift)
:fn (ig/ref :app.storage/gc-deleted-task)} :fn (ig/ref :app.storage/gc-deleted-task)}
{:id "storage-touched-gc" {:id "storage-touched-gc"
:cron #app/cron "0 30 */6 * * ?" ;; every 6 hours :cron #app/cron "0 0 2 */1 * ?" ;; daily (2 hour shift)
:fn (ig/ref :app.storage/gc-touched-task)} :fn (ig/ref :app.storage/gc-touched-task)}
{:id "storage-recheck" {:id "storage-recheck"
:cron #app/cron "0 0 */6 * * ?" ;; every 6 hours :cron #app/cron "0 0 */1 * * ?" ;; hourly
:fn (ig/ref :app.storage/recheck-task)} :fn (ig/ref :app.storage/recheck-task)}
{:id "tasks-gc" {:id "tasks-gc"
@ -260,7 +260,7 @@
:app.tasks.file-xlog-gc/handler :app.tasks.file-xlog-gc/handler
{:pool (ig/ref :app.db/pool) {:pool (ig/ref :app.db/pool)
:metrics (ig/ref :app.metrics/metrics) :metrics (ig/ref :app.metrics/metrics)
:max-age (dt/duration {:hours 24})} :max-age (dt/duration {:hours 48})}
:app.tasks.telemetry/handler :app.tasks.telemetry/handler
{:pool (ig/ref :app.db/pool) {:pool (ig/ref :app.db/pool)

View file

@ -175,7 +175,12 @@
(ex/raise :type :internal (ex/raise :type :internal
:code :rlimit-not-configured :code :rlimit-not-configured
:hint ":image rlimit not configured")) :hint ":image rlimit not configured"))
(rlm/execute rlimit (process params)))) (try
(rlm/execute rlimit (process params))
(catch org.im4java.core.InfoException e
(ex/raise :type :validation
:code :invalid-image
:cause e)))))
;; --- Utility functions ;; --- Utility functions

View file

@ -145,6 +145,9 @@
{:name "0044-add-storage-refcount" {:name "0044-add-storage-refcount"
:fn (mg/resource "app/migrations/sql/0044-add-storage-refcount.sql")} :fn (mg/resource "app/migrations/sql/0044-add-storage-refcount.sql")}
{:name "0045-add-index-to-file-change-table"
:fn (mg/resource "app/migrations/sql/0045-add-index-to-file-change-table.sql")}
]) ])

View file

@ -0,0 +1,2 @@
CREATE INDEX file_change__created_at_idx
ON file_change (created_at);

View file

@ -38,7 +38,7 @@
;; --- Create File Media object (upload) ;; --- Create File Media object (upload)
(declare create-file-media-object) (declare create-file-media-object)
(declare select-file-for-update) (declare select-file)
(s/def ::content ::media/upload) (s/def ::content ::media/upload)
(s/def ::is-local ::us/boolean) (s/def ::is-local ::us/boolean)
@ -50,7 +50,7 @@
(sv/defmethod ::upload-file-media-object (sv/defmethod ::upload-file-media-object
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}] [{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
(db/with-atomic [conn pool] (db/with-atomic [conn pool]
(let [file (select-file-for-update conn file-id)] (let [file (select-file conn file-id)]
(teams/check-edition-permissions! conn profile-id (:team-id file)) (teams/check-edition-permissions! conn profile-id (:team-id file))
(-> (assoc cfg :conn conn) (-> (assoc cfg :conn conn)
(create-file-media-object params))))) (create-file-media-object params)))))
@ -66,9 +66,18 @@
[info] [info]
(= (:mtype info) "image/svg+xml")) (= (:mtype info) "image/svg+xml"))
(defn- fetch-url
[url]
(try
(http/get! url {:as :byte-array})
(catch Exception e
(ex/raise :type :validation
:code :unable-to-access-to-url
:cause e))))
(defn- download-media (defn- download-media
[{:keys [storage] :as cfg} url] [{:keys [storage] :as cfg} url]
(let [result (http/get! url {:as :byte-array}) (let [result (fetch-url url)
data (:body result) data (:body result)
mtype (get (:headers result) "content-type") mtype (get (:headers result) "content-type")
format (cm/mtype->format mtype)] format (cm/mtype->format mtype)]
@ -129,7 +138,7 @@
(sv/defmethod ::create-file-media-object-from-url (sv/defmethod ::create-file-media-object-from-url
[{:keys [pool storage] :as cfg} {:keys [profile-id file-id url name] :as params}] [{:keys [pool storage] :as cfg} {:keys [profile-id file-id url name] :as params}]
(db/with-atomic [conn pool] (db/with-atomic [conn pool]
(let [file (select-file-for-update conn file-id)] (let [file (select-file conn file-id)]
(teams/check-edition-permissions! conn profile-id (:team-id file)) (teams/check-edition-permissions! conn profile-id (:team-id file))
(let [mobj (download-media cfg url) (let [mobj (download-media cfg url)
content {:filename "tempfile" content {:filename "tempfile"
@ -152,7 +161,7 @@
(sv/defmethod ::clone-file-media-object (sv/defmethod ::clone-file-media-object
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}] [{:keys [pool] :as cfg} {:keys [profile-id file-id] :as params}]
(db/with-atomic [conn pool] (db/with-atomic [conn pool]
(let [file (select-file-for-update conn file-id)] (let [file (select-file conn file-id)]
(teams/check-edition-permissions! conn profile-id (:team-id file)) (teams/check-edition-permissions! conn profile-id (:team-id file))
(-> (assoc cfg :conn conn) (-> (assoc cfg :conn conn)
@ -175,17 +184,17 @@
;; --- HELPERS ;; --- HELPERS
(def ^:private sql:select-file-for-update (def ^:private
sql:select-file
"select file.*, "select file.*,
project.team_id as team_id project.team_id as team_id
from file from file
inner join project on (project.id = file.project_id) inner join project on (project.id = file.project_id)
where file.id = ? where file.id = ?")
for update of file")
(defn- select-file-for-update (defn- select-file
[conn id] [conn id]
(let [row (db/exec-one! conn [sql:select-file-for-update id])] (let [row (db/exec-one! conn [sql:select-file id])]
(when-not row (when-not row
(ex/raise :type :not-found)) (ex/raise :type :not-found))
row)) row))

View file

@ -72,3 +72,17 @@
(let [profile (prof/retrieve-profile-data-by-email conn user-email) (let [profile (prof/retrieve-profile-data-by-email conn user-email)
profile (merge profile (prof/retrieve-additional-data conn (:id profile)))] profile (merge profile (prof/retrieve-additional-data conn (:id profile)))]
(pid/create-profile-initial-data conn file profile))))) (pid/create-profile-initial-data conn file profile)))))
;; Migrate
(defn update-file-data-blob-format
[system]
(db/with-atomic [conn (:app.db/pool system)]
(doseq [id (->> (db/exec! conn ["select id from file;"]) (map :id))]
(let [{:keys [data]} (db/get-by-id conn :file id {:columns [:id :data]})]
(prn "Updating file:" id)
(db/update! conn :file
{:data (-> (blob/decode data)
(blob/encode {:version 2}))}
{:id id})))))

View file

@ -121,11 +121,16 @@
(defn parse (defn parse
[data] [data]
(with-open [istream (IOUtils/toInputStream data "UTF-8")] (try
(xml/parse istream))) (with-open [istream (IOUtils/toInputStream data "UTF-8")]
(xml/parse istream))
(catch org.xml.sax.SAXParseException _e
(ex/raise :type :validation
:code :invalid-svg-file))))
(defn process-request (defn process-request
[{:keys [svgc] :as cfg} body] [{:keys [svgc] :as cfg} body]
(let [data (slurp body) (let [data (slurp body)
data (svgc data)] data (svgc data)]
(parse data))) (parse data)))

View file

@ -63,6 +63,7 @@
:uri (:uri cfg) :uri (:uri cfg)
:headers {"content-type" "application/json"} :headers {"content-type" "application/json"}
:body (json/encode-str data)})] :body (json/encode-str data)})]
(when (not= 200 (:status response)) (when (not= 200 (:status response))
(ex/raise :type :internal (ex/raise :type :internal
:code :invalid-response-from-google :code :invalid-response-from-google
@ -129,7 +130,7 @@
[{:keys [conn version]}] [{:keys [conn version]}]
(merge (merge
{:version version {:version version
:with-taiga (:telemetry-with-taiga cfg/config) :with-taiga (:telemetry-with-taiga cfg/config false)
:total-teams (retrieve-num-teams conn) :total-teams (retrieve-num-teams conn)
:total-projects (retrieve-num-projects conn) :total-projects (retrieve-num-projects conn)
:total-files (retrieve-num-files conn)} :total-files (retrieve-num-files conn)}

View file

@ -12,6 +12,7 @@
[app.common.spec :as us] [app.common.spec :as us]
[app.db :as db] [app.db :as db]
[app.http.middleware :refer [wrap-parse-request-body]] [app.http.middleware :refer [wrap-parse-request-body]]
[clojure.pprint :refer [pprint]]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[clojure.tools.logging :as log] [clojure.tools.logging :as log]
[integrant.core :as ig] [integrant.core :as ig]
@ -87,7 +88,12 @@
(catch Exception e (catch Exception e
;; We don't want notify user of a error, just log it for posible ;; We don't want notify user of a error, just log it for posible
;; future investigation. ;; future investigation.
(log/warnf e "Unexpected error on telemetry."))) (log/warn e (str "Unexpected error on telemetry:\n"
(when-let [edata (ex-data e)]
(str "ex-data: \n"
(with-out-str (pprint edata))))
(str "params: \n"
(with-out-str (pprint params)))))))
{:status 200 {:status 200
:body "OK\n"}) :body "OK\n"})

View file

@ -830,6 +830,12 @@
"es" : "Actualizado: %s" "es" : "Actualizado: %s"
} }
}, },
"errors.google-auth-not-enabled" : {
"translations" : {
"en" : "Authentication with google disabled on backend",
"es" : "Autenticación con google esta dehabilitada en el servidor"
}
},
"errors.auth.unauthorized" : { "errors.auth.unauthorized" : {
"used-in" : [ "src/app/main/ui/auth/login.cljs:89" ], "used-in" : [ "src/app/main/ui/auth/login.cljs:89" ],
"translations" : { "translations" : {

View file

@ -137,7 +137,8 @@
(d/index-by :id) (d/index-by :id)
(assoc state :comment-threads))) (assoc state :comment-threads)))
(on-error [{:keys [type] :as err}] (on-error [{:keys [type] :as err}]
(if (= :authentication type) (if (or (= :authentication type)
(= :not-found type))
(rx/empty) (rx/empty)
(rx/throw err)))] (rx/throw err)))]

View file

@ -417,13 +417,22 @@
(defn- handle-upload-error [on-error stream] (defn- handle-upload-error [on-error stream]
(->> stream (->> stream
(rx/catch (rx/catch
(fn on-error [error] (fn on-error* [error]
(if (ex/ex-info? error) (if (ex/ex-info? error)
(on-error (ex-data error)) (on-error* (ex-data error))
(cond (cond
(= (:code error) :invalid-svg-file)
(rx/of (dm/error (tr "errors.media-type-not-allowed")))
(= (:code error) :media-type-not-allowed) (= (:code error) :media-type-not-allowed)
(rx/of (dm/error (tr "errors.media-type-not-allowed"))) (rx/of (dm/error (tr "errors.media-type-not-allowed")))
(= (:code error) :ubable-to-access-to-url)
(rx/of (dm/error (tr "errors.media-type-not-allowed")))
(= (:code error) :invalid-image)
(rx/of (dm/error (tr "errors.media-type-not-allowed")))
(= (:code error) :media-too-large) (= (:code error) :media-too-large)
(rx/of (dm/error (tr "errors.media-too-large"))) (rx/of (dm/error (tr "errors.media-too-large")))

View file

@ -37,7 +37,9 @@
(dom/prevent-default event) (dom/prevent-default event)
(->> (rp/mutation! :login-with-google {}) (->> (rp/mutation! :login-with-google {})
(rx/subs (fn [{:keys [redirect-uri] :as rsp}] (rx/subs (fn [{:keys [redirect-uri] :as rsp}]
(.replace js/location redirect-uri))))) (.replace js/location redirect-uri))
(fn [{:keys [type] :as error}]
(st/emit! (dm/error (tr "errors.google-auth-not-enabled")))))))
(defn- login-with-gitlab (defn- login-with-gitlab
[event] [event]