mirror of
https://github.com/logseq/logseq.git
synced 2026-05-25 21:24:21 +00:00
[codex] improve sync onboarding (#12676)
* enhance: improve sync onboarding * chore: update sync onboarding local changes * fix: show sync upload in native header * fix: route native local sync taps * fix: use upload icon for native local sync * chore: remove debug log * fix: compile cljs tests * test: remove header compile dependency * test: remove mobile header compile dependency
This commit is contained in:
@@ -79,6 +79,7 @@ object MaterialIconResolver {
|
||||
"go-to", "goto" -> Icons.Outlined.Explore
|
||||
"bookmark" -> Icons.Filled.Bookmarks
|
||||
"sync" -> Icons.Outlined.Equalizer
|
||||
"cloud", "cloud-upload", "icloud-and-arrow-up" -> Icons.Filled.CloudUpload
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[frontend.components.export :as export]
|
||||
[frontend.components.page-menu :as page-menu]
|
||||
[frontend.components.plugins :as plugins]
|
||||
[frontend.components.repo :as repo]
|
||||
[frontend.components.right-sidebar :as sidebar]
|
||||
[frontend.components.rtc.indicator :as rtc-indicator]
|
||||
[frontend.components.server :as server]
|
||||
@@ -53,6 +54,24 @@
|
||||
(t :nav/home)
|
||||
{:trigger-props {:as-child true}}))
|
||||
|
||||
(defn current-local-uploadable-graph
|
||||
[]
|
||||
(let [current-repo (state/get-current-repo)]
|
||||
(some (fn [{:keys [url] :as graph}]
|
||||
(when (and (= current-repo url)
|
||||
(repo/local-uploadable-graph? graph))
|
||||
graph))
|
||||
(state/get-repos))))
|
||||
|
||||
(defn local-graph-sync-button
|
||||
[graph]
|
||||
(ui/tooltip
|
||||
(shui/button-ghost-icon :cloud
|
||||
{:class "local-graph-sync-btn"
|
||||
:on-click #(repo/upload-local-graph-with-confirm! graph)})
|
||||
(t :graph/use-sync-beta)
|
||||
{:trigger-props {:as-child true}}))
|
||||
|
||||
(rum/defcs rtc-collaborators <
|
||||
rum/reactive
|
||||
(rum/local nil ::online-users)
|
||||
@@ -449,6 +468,9 @@
|
||||
(rtc-indicator/uploading-detail))
|
||||
(search-index-progress)
|
||||
|
||||
(when-let [graph (current-local-uploadable-graph)]
|
||||
(local-graph-sync-button graph))
|
||||
|
||||
(when (and (not= (state/get-current-route) :home)
|
||||
(not custom-home-page?))
|
||||
(home-button))
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
[frontend.config :as config]
|
||||
[frontend.context.i18n :as i18n :refer [t]]
|
||||
[frontend.db :as db]
|
||||
[frontend.handler.db-based.rtc-flows :as rtc-flows]
|
||||
[frontend.handler.db-based.sync :as rtc-handler]
|
||||
[frontend.handler.graph :as graph]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.repo :as repo-handler]
|
||||
[frontend.handler.route :as route-handler]
|
||||
[frontend.handler.user :as user-handler]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.state :as state]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.util :as util]
|
||||
@@ -25,16 +25,72 @@
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(defn graph-sync-icon-name
|
||||
[{:keys [remote? graph-e2ee?]}]
|
||||
(when remote?
|
||||
(if graph-e2ee? "lock" "cloud")))
|
||||
|
||||
(defn local-uploadable-graph?
|
||||
[{:keys [root remote?]}]
|
||||
(and (or root
|
||||
(mobile-util/native-platform?))
|
||||
(not remote?)
|
||||
(user-handler/logged-in?)
|
||||
(user-handler/rtc-group?)))
|
||||
|
||||
(defn- graph-e2ee-enabled?
|
||||
[{:keys [url graph-e2ee?] :as graph}]
|
||||
(if (contains? graph :graph-e2ee?)
|
||||
(true? graph-e2ee?)
|
||||
(if (= url (state/get-current-repo))
|
||||
(let [e2ee? (ldb/get-graph-rtc-e2ee? (db/get-db))]
|
||||
(if (nil? e2ee?) true (true? e2ee?)))
|
||||
true)))
|
||||
|
||||
(defn- <ensure-current-graph-for-upload!
|
||||
[repo]
|
||||
(if (= repo (state/get-current-repo))
|
||||
(p/resolved nil)
|
||||
(state/pub-event! [:graph/switch repo])))
|
||||
|
||||
(defn upload-local-graph-with-confirm!
|
||||
[{:keys [url] :as graph}]
|
||||
(let [graph-name (config/db-graph-name url)
|
||||
dialog-config {:cancel-label (t :ui/cancel)
|
||||
:ok-label (t :ui/confirm)}]
|
||||
(-> (shui/dialog-confirm!
|
||||
[:p.font-medium.-my-4 (t :graph/upload-local-confirm-desc graph-name)]
|
||||
dialog-config)
|
||||
(p/then
|
||||
(fn []
|
||||
(p/let [_ (<ensure-current-graph-for-upload! url)
|
||||
graph-e2ee? (graph-e2ee-enabled? graph)]
|
||||
(let [mobile? (util/mobile?)
|
||||
hide-upload-log! (fn []
|
||||
(when mobile?
|
||||
(shui/popup-hide! :rtc-graph-upload-log)))]
|
||||
(when mobile?
|
||||
(shui/popup-show! nil
|
||||
(fn []
|
||||
(rtc-indicator/uploading-logs))
|
||||
{:id :rtc-graph-upload-log}))
|
||||
(rtc-indicator/on-upload-finished-task
|
||||
hide-upload-log!)
|
||||
(-> (rtc-handler/<rtc-upload-graph! url graph-e2ee?)
|
||||
(p/finally hide-upload-log!)))))))))
|
||||
|
||||
(rum/defc normalized-graph-label
|
||||
[{:keys [url remote? graph-e2ee?] :as graph} on-click]
|
||||
[{:keys [url remote?] :as graph} on-click]
|
||||
(when graph
|
||||
[:span.flex.items-center
|
||||
(let [local-dir (config/get-local-dir url)
|
||||
graph-name (text-util/get-graph-name-from-path url)]
|
||||
[:a.flex.items-center {:title local-dir
|
||||
:on-click #(on-click graph)}
|
||||
[:span graph-name]
|
||||
(when remote? [:strong.px-1.flex.items-center (ui/icon (if graph-e2ee? "lock" "cloud"))])])]))
|
||||
[:<>
|
||||
[:a.flex.items-center {:title local-dir
|
||||
:on-click #(on-click graph)}
|
||||
[:span graph-name]
|
||||
(when remote?
|
||||
[:strong.px-1.flex.items-center (ui/icon (graph-sync-icon-name graph))])]])]))
|
||||
|
||||
(defn sort-repos-with-metadata-local
|
||||
[repos]
|
||||
@@ -122,6 +178,7 @@
|
||||
:class "delete-local-graph-menu-item"
|
||||
:on-click #(delete-local-graph! repo)}
|
||||
(t :graph/delete-local-action)))
|
||||
|
||||
(when (and root
|
||||
(user-handler/logged-in?)
|
||||
(user-handler/rtc-group?)
|
||||
@@ -130,26 +187,7 @@
|
||||
(shui/dropdown-menu-item
|
||||
{:key "logseq-sync"
|
||||
:class "use-logseq-sync-menu-item"
|
||||
:on-click (fn []
|
||||
(let [repo (state/get-current-repo)
|
||||
token (state/get-auth-id-token)
|
||||
remote-graph-name (config/db-graph-name (state/get-current-repo))
|
||||
graph-e2ee? (let [e2ee? (ldb/get-graph-rtc-e2ee? (db/get-db))]
|
||||
(if (nil? e2ee?) true (true? e2ee?)))]
|
||||
(when (and token remote-graph-name)
|
||||
(rtc-handler/<rtc-upload-graph! repo graph-e2ee?)
|
||||
(when (util/mobile?)
|
||||
(shui/popup-show! nil
|
||||
(fn []
|
||||
(rtc-indicator/uploading-logs))
|
||||
{:id :rtc-graph-upload-log}))
|
||||
|
||||
(rtc-indicator/on-upload-finished-task
|
||||
(fn []
|
||||
(when (util/mobile?) (shui/popup-hide! :rtc-graph-upload-log))
|
||||
(p/do!
|
||||
(rtc-flows/trigger-rtc-start repo)
|
||||
(rtc-handler/<get-remote-graphs)))))))}
|
||||
:on-click #(upload-local-graph-with-confirm! repo)}
|
||||
(t :graph/use-sync-beta)))
|
||||
|
||||
(when (and remote?
|
||||
@@ -448,7 +486,8 @@
|
||||
(ui/tooltip
|
||||
[:a.item.flex.items-center.gap-1.select-none
|
||||
selector-opts
|
||||
[:span.thumb (shui/tabler-icon (if remote? "cloud" "topology-star") {:size 16})]
|
||||
[:span.thumb
|
||||
(shui/tabler-icon (if remote? "cloud" "topology-star") {:size 16})]
|
||||
[:strong short-repo-name]
|
||||
(shui/tabler-icon "selector" {:size 18})]
|
||||
current-repo)]))
|
||||
|
||||
@@ -355,8 +355,10 @@
|
||||
|
||||
(defn rtc-group?
|
||||
[]
|
||||
(boolean (or (some? (config/get-custom-sync-server-url))
|
||||
(seq (set/intersection (state/user-groups) #{"team" "rtc_2025_07_10"})))))
|
||||
(boolean (or
|
||||
config/dev?
|
||||
(some? (config/get-custom-sync-server-url))
|
||||
(seq (set/intersection (state/user-groups) #{"team" "rtc_2025_07_10"})))))
|
||||
|
||||
(defn alpha-user?
|
||||
[]
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
(defonce ^:private *graph->aes-key (atom {}))
|
||||
(defonce ^:private *user-rsa-key-pair-inflight (atom {}))
|
||||
(defonce ^:private *ensure-user-rsa-key-pair-inflight (atom {}))
|
||||
(defonce ^:private node-default-auth-file "~/logseq/auth.json")
|
||||
(defonce ^:private e2ee-password-secret-key "logseq-encrypted-password")
|
||||
(def ^:private invalid-transit ::invalid-transit)
|
||||
@@ -377,7 +378,8 @@
|
||||
exported-public-key (crypt/<export-public-key publicKey)
|
||||
public-key-str (ldb/write-transit-str exported-public-key)
|
||||
encrypted-private-key-str (ldb/write-transit-str encrypted-private-key)]
|
||||
(p/let [_ (<upload-user-rsa-key-pair! base public-key-str encrypted-private-key-str)]
|
||||
(p/let [_ (<save-e2ee-password password)
|
||||
_ (<upload-user-rsa-key-pair! base public-key-str encrypted-private-key-str)]
|
||||
{:public-key public-key-str
|
||||
:encrypted-private-key encrypted-private-key-str
|
||||
:password password})))
|
||||
@@ -404,13 +406,31 @@
|
||||
:else
|
||||
(<generate-and-upload-user-rsa-key-pair! base opts))))
|
||||
|
||||
(defn- <ensure-user-rsa-key-pair
|
||||
[base {:keys [password ensure-server? server-rsa-keys-exists?] :as opts}]
|
||||
(if (seq password)
|
||||
(<ensure-user-rsa-key-pair-raw base opts)
|
||||
(p/let [user-id (<resolve-user-uuid)]
|
||||
(when-not (and (string? base) (string? user-id))
|
||||
(fail-fast :db-sync/missing-field {:base base
|
||||
:user-id user-id
|
||||
:field :user-rsa-key-pair}))
|
||||
(let [k [base user-id ensure-server? server-rsa-keys-exists?]]
|
||||
(if-let [inflight (get @*ensure-user-rsa-key-pair-inflight k)]
|
||||
inflight
|
||||
(let [task (-> (<ensure-user-rsa-key-pair-raw base opts)
|
||||
(p/finally (fn []
|
||||
(swap! *ensure-user-rsa-key-pair-inflight dissoc k))))]
|
||||
(swap! *ensure-user-rsa-key-pair-inflight assoc k task)
|
||||
task))))))
|
||||
|
||||
(defn ensure-user-rsa-keys!
|
||||
([]
|
||||
(ensure-user-rsa-keys! nil))
|
||||
([opts]
|
||||
(let [base (e2ee-base)]
|
||||
(if (string? base)
|
||||
(<ensure-user-rsa-key-pair-raw base opts)
|
||||
(<ensure-user-rsa-key-pair base opts)
|
||||
(do
|
||||
(log/info :db-sync/skip-ensure-user-rsa-keys {:reason :missing-e2ee-base})
|
||||
(p/resolved nil))))))
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
[rum.core :as rum]))
|
||||
|
||||
(defonce native-top-bar-listener? (atom false))
|
||||
(defonce native-top-bar-listener-version (atom nil))
|
||||
(def ^:private native-top-bar-listener-current-version :sync-upload-v2)
|
||||
|
||||
(defn- open-journal-calendar! []
|
||||
(let [apply-date! (fn [date]
|
||||
@@ -113,10 +115,19 @@
|
||||
(t :mobile.header/create-graph))])
|
||||
{:default-height false}))
|
||||
|
||||
(defn current-local-uploadable-graph
|
||||
[]
|
||||
(let [current-repo (state/get-current-repo)]
|
||||
(some (fn [{:keys [url] :as graph}]
|
||||
(when (and (= current-repo url)
|
||||
(repo/local-uploadable-graph? graph))
|
||||
graph))
|
||||
(state/get-repos))))
|
||||
|
||||
(defn- register-native-top-bar-events! [*configure-top-bar-f]
|
||||
(when (and (mobile-util/native-platform?)
|
||||
mobile-util/native-top-bar
|
||||
(not @native-top-bar-listener?))
|
||||
(not= native-top-bar-listener-current-version @native-top-bar-listener-version))
|
||||
(.addListener ^js mobile-util/native-top-bar "buttonTapped"
|
||||
(fn [^js e]
|
||||
(case (.-id e)
|
||||
@@ -130,9 +141,11 @@
|
||||
"add-graph" (state/pub-event! [:graph/new-db-graph])
|
||||
"home-setting" (open-home-settings-actions!)
|
||||
"graph-setting" (open-graph-settings-actions!)
|
||||
"sync" (shui/popup-show! nil
|
||||
(rtc-indicator/details)
|
||||
{})
|
||||
"sync" (if-let [graph (current-local-uploadable-graph)]
|
||||
(repo/upload-local-graph-with-confirm! graph)
|
||||
(shui/popup-show! nil
|
||||
(rtc-indicator/details)
|
||||
{}))
|
||||
"favorite" (when-let [id (state/get-current-page)]
|
||||
(when (common-util/uuid-string? id)
|
||||
(when-let [block (db/entity [:block/uuid (uuid id)])]
|
||||
@@ -150,10 +163,11 @@
|
||||
(open-page-settings block))))
|
||||
|
||||
nil)))
|
||||
(reset! native-top-bar-listener? true)))
|
||||
(reset! native-top-bar-listener? true)
|
||||
(reset! native-top-bar-listener-version native-top-bar-listener-current-version)))
|
||||
|
||||
(defn- configure-native-top-bar!
|
||||
[{:keys [tab title route-name route-view sync-color favorited? show-sync?]}]
|
||||
[{:keys [tab title route-name route-view sync-color favorited? show-sync? show-local-upload?]}]
|
||||
(when (and (mobile-util/native-platform?)
|
||||
mobile-util/native-top-bar)
|
||||
(let [hidden? (and (mobile-util/native-ios?) (= tab "search"))
|
||||
@@ -177,7 +191,10 @@
|
||||
(cond-> []
|
||||
(nil? route-view)
|
||||
(conj {:id "home-setting" :systemIcon "ellipsis"})
|
||||
(and show-sync? (not page?))
|
||||
(and show-local-upload? (not page?))
|
||||
(conj {:id "sync" :systemIcon "icloud.and.arrow.up"
|
||||
:size "medium"})
|
||||
(and (not show-local-upload?) show-sync? (not page?))
|
||||
(conj {:id "sync" :systemIcon "circle.fill" :color sync-color
|
||||
:size "small"}))
|
||||
|
||||
@@ -212,7 +229,9 @@
|
||||
rtc-state (:rtc-state detail-info)
|
||||
graph-uuid (or (:graph-uuid detail-info)
|
||||
(ldb/get-graph-rtc-uuid (db/get-db)))
|
||||
local-uploadable-graph (current-local-uploadable-graph)
|
||||
show-sync? (and current-repo graph-uuid (user-handler/logged-in?))
|
||||
show-local-upload? (some? local-uploadable-graph)
|
||||
unpushed-block-update-count (:pending-local-ops detail-info)
|
||||
pending-asset-ops (:pending-asset-ops detail-info)
|
||||
fallback-title (cond
|
||||
@@ -253,11 +272,12 @@
|
||||
:route-view route-view
|
||||
:sync-color sync-color
|
||||
:show-sync? show-sync?
|
||||
:show-local-upload? show-local-upload?
|
||||
:favorited? favorited?}))]
|
||||
(reset! *configure-top-bar-f f)
|
||||
(f favorited?)))
|
||||
nil)
|
||||
[current-repo tab route-name route-view route-id fallback-title sync-color show-sync? page-route?])
|
||||
[current-repo tab route-name route-view route-id fallback-title sync-color show-sync? show-local-upload? page-route?])
|
||||
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
@@ -282,13 +302,14 @@
|
||||
:route-view route-view
|
||||
:sync-color sync-color
|
||||
:show-sync? show-sync?
|
||||
:show-local-upload? show-local-upload?
|
||||
:favorited? favorited?}))]
|
||||
(reset! *configure-top-bar-f f)
|
||||
(f favorited?)))))
|
||||
(p/catch (fn [_] nil)))
|
||||
#(reset! cancelled? true))
|
||||
nil))
|
||||
[current-repo tab route-name route-view route-id sync-color show-sync? page-route?])
|
||||
[current-repo tab route-name route-view route-id sync-color show-sync? show-local-upload? page-route?])
|
||||
|
||||
[:<>]))
|
||||
|
||||
|
||||
@@ -736,6 +736,7 @@
|
||||
:graph/time-travel-now "Now"
|
||||
:graph/toggle-tag "Toggle tag {1}"
|
||||
:graph/updated-switching "Graph updated! Switching to graph ..."
|
||||
:graph/upload-local-confirm-desc "Upload graph \"{1}\" to Logseq Server?"
|
||||
:graph/use-sync-beta "Use Logseq Sync (Beta testing)"
|
||||
:graph/use-sync-label "Use Logseq Sync?"
|
||||
:graph/view-mode "View mode"
|
||||
|
||||
@@ -732,6 +732,7 @@
|
||||
:graph/time-travel-now "现在"
|
||||
:graph/toggle-tag "切换标签 {1}"
|
||||
:graph/updated-switching "图谱已更新!正在切换到图谱……"
|
||||
:graph/upload-local-confirm-desc "要将图谱“{1}”上传到 Logseq Server 吗?"
|
||||
:graph/use-sync-beta "使用 Logseq Sync(Beta 测试)"
|
||||
:graph/use-sync-label "使用 Logseq Sync?"
|
||||
:graph/view-mode "视图模式"
|
||||
|
||||
@@ -1,14 +1,170 @@
|
||||
(ns frontend.components.repo-test
|
||||
(:require [cljs.test :refer [deftest is async]]
|
||||
[frontend.components.repo :as repo]
|
||||
[frontend.components.rtc.indicator :as rtc-indicator]
|
||||
[frontend.db :as db]
|
||||
[frontend.handler.db-based.sync :as rtc-handler]
|
||||
[frontend.handler.repo :as repo-handler]
|
||||
[frontend.handler.user :as user-handler]
|
||||
[frontend.state :as state]
|
||||
[frontend.mobile.util :as mobile-util]
|
||||
[frontend.util :as util]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.shui.ui :as shui]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn- ensure-rsa-key-fn
|
||||
[]
|
||||
#'repo/ensure-e2ee-rsa-key-for-cloud!)
|
||||
|
||||
(deftest local-uploadable-graph-allows-native-mobile-local-graph-without-root-test
|
||||
(with-redefs [mobile-util/native-platform? (constantly true)
|
||||
user-handler/logged-in? (constantly true)
|
||||
user-handler/rtc-group? (constantly true)]
|
||||
(is (true? (repo/local-uploadable-graph? {:url "logseq_db_mobile"})))))
|
||||
|
||||
(deftest upload-local-graph-with-confirm-asks-before-upload-test
|
||||
(async done
|
||||
(let [upload-fn (some-> (resolve 'frontend.components.repo/upload-local-graph-with-confirm!) deref)
|
||||
dialogs (atom [])
|
||||
upload-calls (atom [])
|
||||
finished-calls (atom 0)]
|
||||
(if-not upload-fn
|
||||
(do
|
||||
(is false "missing upload-local-graph-with-confirm!")
|
||||
(done))
|
||||
(-> (p/with-redefs [shui/dialog-confirm! (fn [content opts]
|
||||
(swap! dialogs conj {:content content
|
||||
:opts opts})
|
||||
(p/resolved nil))
|
||||
rtc-handler/<rtc-upload-graph! (fn [repo graph-e2ee?]
|
||||
(swap! upload-calls conj [repo graph-e2ee?])
|
||||
(p/resolved nil))
|
||||
state/get-current-repo (fn []
|
||||
"logseq_db_demo")
|
||||
rtc-indicator/on-upload-finished-task (fn [f]
|
||||
(swap! finished-calls inc)
|
||||
(f))
|
||||
util/mobile? (fn [] false)
|
||||
shui/popup-show! (fn [& _] nil)
|
||||
shui/popup-hide! (fn [& _] nil)]
|
||||
(upload-fn {:url "logseq_db_demo"
|
||||
:graph-e2ee? true}))
|
||||
(p/then (fn [_]
|
||||
(is (= 1 (count @dialogs)))
|
||||
(is (= [["logseq_db_demo" true]] @upload-calls))
|
||||
(is (= 1 @finished-calls))
|
||||
(done)))
|
||||
(p/catch (fn [error]
|
||||
(is false (str error))
|
||||
(done))))))))
|
||||
|
||||
(deftest upload-local-graph-switches-before-uploading-non-current-graph-test
|
||||
(async done
|
||||
(let [upload-fn (some-> (resolve 'frontend.components.repo/upload-local-graph-with-confirm!) deref)
|
||||
current-repo (atom "logseq_db_current")
|
||||
calls (atom [])]
|
||||
(if-not upload-fn
|
||||
(do
|
||||
(is false "missing upload-local-graph-with-confirm!")
|
||||
(done))
|
||||
(-> (p/with-redefs [shui/dialog-confirm! (fn [_content _opts]
|
||||
(p/resolved nil))
|
||||
state/get-current-repo (fn []
|
||||
@current-repo)
|
||||
state/pub-event! (fn [event]
|
||||
(swap! calls conj event)
|
||||
(reset! current-repo (second event))
|
||||
(p/resolved nil))
|
||||
db/get-db (fn []
|
||||
:db-after-switch)
|
||||
ldb/get-graph-rtc-e2ee? (fn [db]
|
||||
(is (= :db-after-switch db))
|
||||
false)
|
||||
rtc-handler/<rtc-upload-graph! (fn [repo graph-e2ee?]
|
||||
(swap! calls conj [:upload repo graph-e2ee?])
|
||||
(p/resolved nil))
|
||||
rtc-indicator/on-upload-finished-task (fn [f]
|
||||
(f))
|
||||
util/mobile? (fn [] false)
|
||||
shui/popup-show! (fn [& _] nil)
|
||||
shui/popup-hide! (fn [& _] nil)]
|
||||
(upload-fn {:url "logseq_db_other"}))
|
||||
(p/then (fn [_]
|
||||
(is (= [[:graph/switch "logseq_db_other"]
|
||||
[:upload "logseq_db_other" false]]
|
||||
@calls))
|
||||
(done)))
|
||||
(p/catch (fn [error]
|
||||
(is false (str error))
|
||||
(done))))))))
|
||||
|
||||
(deftest upload-local-graph-shows-mobile-popup-before-upload-starts-test
|
||||
(async done
|
||||
(let [upload-fn (some-> (resolve 'frontend.components.repo/upload-local-graph-with-confirm!) deref)
|
||||
calls (atom [])]
|
||||
(if-not upload-fn
|
||||
(do
|
||||
(is false "missing upload-local-graph-with-confirm!")
|
||||
(done))
|
||||
(-> (p/with-redefs [shui/dialog-confirm! (fn [_content _opts]
|
||||
(p/resolved nil))
|
||||
state/get-current-repo (fn []
|
||||
"logseq_db_demo")
|
||||
rtc-handler/<rtc-upload-graph! (fn [_repo _graph-e2ee?]
|
||||
(swap! calls conj :upload)
|
||||
(is (= [:popup-show :finish-handler :upload] @calls))
|
||||
(p/resolved nil))
|
||||
rtc-indicator/on-upload-finished-task (fn [_f]
|
||||
(swap! calls conj :finish-handler))
|
||||
util/mobile? (fn [] true)
|
||||
shui/popup-show! (fn [& _]
|
||||
(swap! calls conj :popup-show))
|
||||
shui/popup-hide! (fn [& _]
|
||||
(swap! calls conj :popup-hide))]
|
||||
(upload-fn {:url "logseq_db_demo"
|
||||
:graph-e2ee? true}))
|
||||
(p/then (fn [_]
|
||||
(is (= [:popup-show :finish-handler :upload :popup-hide]
|
||||
@calls))
|
||||
(done)))
|
||||
(p/catch (fn [error]
|
||||
(is false (str error))
|
||||
(done))))))))
|
||||
|
||||
(deftest upload-local-graph-hides-mobile-popup-when-upload-errors-test
|
||||
(async done
|
||||
(let [upload-fn (some-> (resolve 'frontend.components.repo/upload-local-graph-with-confirm!) deref)
|
||||
calls (atom [])]
|
||||
(if-not upload-fn
|
||||
(do
|
||||
(is false "missing upload-local-graph-with-confirm!")
|
||||
(done))
|
||||
(-> (p/with-redefs [shui/dialog-confirm! (fn [_content _opts]
|
||||
(p/resolved nil))
|
||||
state/get-current-repo (fn []
|
||||
"logseq_db_demo")
|
||||
rtc-handler/<rtc-upload-graph! (fn [_repo _graph-e2ee?]
|
||||
(swap! calls conj :upload)
|
||||
(p/rejected (ex-info "upload failed" {})))
|
||||
rtc-indicator/on-upload-finished-task (fn [_f]
|
||||
(swap! calls conj :finish-handler))
|
||||
util/mobile? (fn [] true)
|
||||
shui/popup-show! (fn [& _]
|
||||
(swap! calls conj :popup-show))
|
||||
shui/popup-hide! (fn [& _]
|
||||
(swap! calls conj :popup-hide))]
|
||||
(upload-fn {:url "logseq_db_demo"
|
||||
:graph-e2ee? true}))
|
||||
(p/then (fn [_]
|
||||
(is false "expected upload failure")
|
||||
(done)))
|
||||
(p/catch (fn [error]
|
||||
(is (= "upload failed" (ex-message error)))
|
||||
(is (= [:popup-show :finish-handler :upload :popup-hide]
|
||||
@calls))
|
||||
(done))))))))
|
||||
|
||||
(deftest ensure-rsa-key-does-not-create-graph-test
|
||||
(async done
|
||||
(let [ensure-fn (ensure-rsa-key-fn)
|
||||
|
||||
@@ -551,6 +551,105 @@
|
||||
(is (not= ":public-key is not ISeqable" (ex-message e))))))
|
||||
(p/finally done))))
|
||||
|
||||
(deftest ensure-user-rsa-keys-saves-new-ui-password-test
|
||||
(async done
|
||||
(let [upload-calls (atom [])
|
||||
save-calls (atom [])]
|
||||
(-> (p/with-redefs [sync-crypt/e2ee-base (fn [] "http://base")
|
||||
sync-crypt/<resolve-user-uuid (fn []
|
||||
(p/resolved "user-1"))
|
||||
sync-crypt/<fetch-user-rsa-key-pair-raw (fn [_base]
|
||||
(p/resolved nil))
|
||||
sync-crypt/<upload-user-rsa-key-pair! (fn [base public-key encrypted-private-key]
|
||||
(swap! upload-calls conj [base public-key encrypted-private-key])
|
||||
(p/resolved {:public-key public-key
|
||||
:encrypted-private-key encrypted-private-key}))
|
||||
sync-crypt/<save-e2ee-password (fn [password]
|
||||
(swap! save-calls conj password)
|
||||
(p/resolved nil))
|
||||
platform/current (fn [] {:env {:runtime :browser}})
|
||||
platform/kv-get (fn [_platform' _k]
|
||||
(p/resolved nil))
|
||||
platform/kv-set! (fn [_platform' _k _value]
|
||||
(p/resolved nil))
|
||||
ui-request/<request (fn [action payload & _opts]
|
||||
(is (= :request-e2ee-password action))
|
||||
(is (= {:reason :generate-user-rsa-key-pair} payload))
|
||||
(p/resolved {:password "new-password"}))
|
||||
crypt/<generate-rsa-key-pair (fn []
|
||||
(p/resolved {:publicKey :public-key
|
||||
:privateKey :private-key}))
|
||||
crypt/<encrypt-private-key (fn [password private-key]
|
||||
(is (= "new-password" password))
|
||||
(is (= :private-key private-key))
|
||||
(p/resolved :encrypted-private-key))
|
||||
crypt/<export-public-key (fn [public-key]
|
||||
(is (= :public-key public-key))
|
||||
(p/resolved :exported-public-key))
|
||||
ldb/write-transit-str pr-str]
|
||||
(sync-crypt/ensure-user-rsa-keys!))
|
||||
(p/then (fn [result]
|
||||
(is (= "new-password" (:password result)))
|
||||
(is (= [["http://base"
|
||||
(pr-str :exported-public-key)
|
||||
(pr-str :encrypted-private-key)]]
|
||||
@upload-calls))
|
||||
(is (= ["new-password"] @save-calls))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest ensure-user-rsa-keys-deduplicates-concurrent-new-user-password-request-test
|
||||
(async done
|
||||
(let [ui-calls (atom 0)
|
||||
upload-calls (atom [])
|
||||
save-calls (atom [])]
|
||||
(-> (p/with-redefs [sync-crypt/e2ee-base (fn [] "http://base")
|
||||
sync-crypt/<resolve-user-uuid (fn []
|
||||
(p/resolved "user-1"))
|
||||
sync-crypt/<fetch-user-rsa-key-pair-raw (fn [_base]
|
||||
(p/let [_ (p/delay 10)]
|
||||
nil))
|
||||
sync-crypt/<upload-user-rsa-key-pair! (fn [base public-key encrypted-private-key]
|
||||
(swap! upload-calls conj [base public-key encrypted-private-key])
|
||||
(p/resolved {:public-key public-key
|
||||
:encrypted-private-key encrypted-private-key}))
|
||||
sync-crypt/<save-e2ee-password (fn [password]
|
||||
(swap! save-calls conj password)
|
||||
(p/resolved nil))
|
||||
platform/current (fn [] {:env {:runtime :browser}})
|
||||
platform/kv-get (fn [_platform' _k]
|
||||
(p/resolved nil))
|
||||
platform/kv-set! (fn [_platform' _k _value]
|
||||
(p/resolved nil))
|
||||
ui-request/<request (fn [action payload & _opts]
|
||||
(is (= :request-e2ee-password action))
|
||||
(is (= {:reason :generate-user-rsa-key-pair} payload))
|
||||
(swap! ui-calls inc)
|
||||
(p/resolved {:password "new-password"}))
|
||||
crypt/<generate-rsa-key-pair (fn []
|
||||
(p/resolved {:publicKey :public-key
|
||||
:privateKey :private-key}))
|
||||
crypt/<encrypt-private-key (fn [password private-key]
|
||||
(is (= "new-password" password))
|
||||
(is (= :private-key private-key))
|
||||
(p/resolved :encrypted-private-key))
|
||||
crypt/<export-public-key (fn [public-key]
|
||||
(is (= :public-key public-key))
|
||||
(p/resolved :exported-public-key))
|
||||
ldb/write-transit-str pr-str]
|
||||
(let [task-1 (sync-crypt/ensure-user-rsa-keys!)
|
||||
task-2 (sync-crypt/ensure-user-rsa-keys!)]
|
||||
(p/all [task-1 task-2])))
|
||||
(p/then (fn [results]
|
||||
(is (= 2 (count results)))
|
||||
(is (= 1 @ui-calls))
|
||||
(is (= 1 (count @upload-calls)))
|
||||
(is (= ["new-password"] @save-calls))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally done)))))
|
||||
|
||||
(deftest decrypt-private-key-headless-ignores-config-e2ee-password-test
|
||||
(async done
|
||||
(let [old-sync-config @worker-state/*db-sync-config
|
||||
|
||||
Reference in New Issue
Block a user