From c19eca0fd6ca774a08444d0d9d37008d3ed6a697 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sat, 9 May 2026 12:18:45 +0800 Subject: [PATCH] fix: handle wrong e2ee password on download --- src/main/frontend/handler/events.cljs | 12 ++----- .../frontend/handler/events/rtc_error.cljs | 30 ++++++++++++++++++ src/main/frontend/worker/sync/download.cljs | 11 ++++--- .../handler/events/rtc_error_test.cljs | 21 +++++++++++++ .../frontend/worker/sync/download_test.cljs | 31 +++++++++++++++++++ 5 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 src/main/frontend/handler/events/rtc_error.cljs create mode 100644 src/test/frontend/handler/events/rtc_error_test.cljs diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index e92c09202b..0e3720ec57 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -24,6 +24,7 @@ [frontend.handler.db-based.rtc-flows :as rtc-flows] [frontend.handler.db-based.sync :as rtc-handler] [frontend.handler.editor :as editor-handler] + [frontend.handler.events.rtc-error :as rtc-error] [frontend.handler.export :as export] [frontend.handler.graph :as graph-handler] [frontend.handler.notification :as notification] @@ -57,13 +58,6 @@ (defmulti handle first) (defonce ^:private *search-index-build-timeout (atom nil)) -(def ^:private decrypt-aes-key-failed-notification - "Failed to decrypt this graph.") - -(defn- decrypt-aes-key-failed? - [error] - (string/includes? (or (ex-message error) (str error)) "decrypt-aes-key")) - (defn- (state/ UI (defmethod handle :db/sync-changes [[_ data]] diff --git a/src/main/frontend/handler/events/rtc_error.cljs b/src/main/frontend/handler/events/rtc_error.cljs new file mode 100644 index 0000000000..366c2fe09a --- /dev/null +++ b/src/main/frontend/handler/events/rtc_error.cljs @@ -0,0 +1,30 @@ +(ns frontend.handler.events.rtc-error + "RTC event error helpers." + (:require [clojure.string :as string])) + +(defn- throwable-message + [error] + (or (ex-message error) + (when (instance? js/Error error) + (.-message error)) + (some-> error str))) + +(defn- error-texts + [error] + (when error + (let [data (ex-data error)] + (concat + [(throwable-message error) + (:error-message data) + (:error-cause data)] + (error-texts (:error data)) + (error-texts (ex-cause error)))))) + +(defn download-decrypt-failed? + [error] + (boolean + (some (fn [text] + (and (string? text) + (or (string/includes? text "decrypt-aes-key") + (string/includes? text "decrypt-private-key")))) + (error-texts error)))) diff --git a/src/main/frontend/worker/sync/download.cljs b/src/main/frontend/worker/sync/download.cljs index 8d2af4c6c7..124330787a 100644 --- a/src/main/frontend/worker/sync/download.cljs +++ b/src/main/frontend/worker/sync/download.cljs @@ -467,10 +467,10 @@ (let [base (sync-auth/http-base-url @worker-state/*db-sync-config)] (if (and (seq repo) (seq graph-id) (seq base)) (let [stage* (atom :init) - import-id* (atom nil)] - (-> (p/let [log-f (fn [payload] - (rtc-log-and-state/rtc-log :rtc.log/download payload)) - _ (log-f {:sub-type :download-progress + import-id* (atom nil) + log-f (fn [payload] + (rtc-log-and-state/rtc-log :rtc.log/download payload))] + (-> (p/let [_ (log-f {:sub-type :download-progress :graph-uuid graph-id :message "Preparing graph snapshot download"}) _ (reset! stage* :fetch-pull) @@ -529,6 +529,9 @@ (p/catch (fn [error] (when-let [import-id @import-id*] (clear-import-state! import-id)) + (log-f {:sub-type :download-completed + :graph-uuid graph-id + :message "Graph snapshot download failed"}) (log/error :db-sync/download-graph-by-id-failed {:repo repo :graph-id graph-id diff --git a/src/test/frontend/handler/events/rtc_error_test.cljs b/src/test/frontend/handler/events/rtc_error_test.cljs new file mode 100644 index 0000000000..bcf27cbd70 --- /dev/null +++ b/src/test/frontend/handler/events/rtc_error_test.cljs @@ -0,0 +1,21 @@ +(ns frontend.handler.events.rtc-error-test + (:require [cljs.test :refer [deftest is]] + [frontend.handler.events.rtc-error :as rtc-error])) + +(deftest download-decrypt-failed-detects-worker-error-data-test + (is (true? + (rtc-error/download-decrypt-failed? + (ex-info "db-sync download failed" + {:error-message "decrypt-private-key"}))))) + +(deftest download-decrypt-failed-detects-nested-error-test + (is (true? + (rtc-error/download-decrypt-failed? + (ex-info "db-sync download failed" + {:error (ex-info "decrypt-aes-key" {})}))))) + +(deftest download-decrypt-failed-ignores-other-errors-test + (is (false? + (rtc-error/download-decrypt-failed? + (ex-info "db-sync download failed" + {:error-message "snapshot download failed"}))))) diff --git a/src/test/frontend/worker/sync/download_test.cljs b/src/test/frontend/worker/sync/download_test.cljs index 7e26ac1f2f..ce8f73fb44 100644 --- a/src/test/frontend/worker/sync/download_test.cljs +++ b/src/test/frontend/worker/sync/download_test.cljs @@ -3,6 +3,7 @@ [frontend.worker.state :as worker-state] [frontend.worker.sync.crypt :as sync-crypt] [frontend.worker.sync.download :as sync-download] + [frontend.worker.sync.log-and-state :as rtc-log-and-state] [logseq.db-sync.snapshot :as snapshot] [promesa.core :as p])) @@ -78,3 +79,33 @@ (set! js/fetch fetch-prev) (reset! worker-state/*db-sync-config config-prev) (done))))))) + +(deftest encrypted-download-failure-emits-completed-log-test + (async done + (let [config-prev @worker-state/*db-sync-config + log-events (atom [])] + (reset! worker-state/*db-sync-config {:http-base "https://sync.example.test"}) + (-> (p/with-redefs [sync-download/fetch-json (fn [_url _opts schema] + (case schema + :sync/pull + (p/resolved {:t 42}) + + :sync/snapshot-download + (p/resolved {:url "https://sync.example.test/snapshot"}) + + (p/rejected (ex-info "unexpected schema" {:schema schema})))) + sync-crypt/