mirror of
https://github.com/logseq/logseq.git
synced 2026-05-15 08:22:23 +00:00
fix: web app can't sync after merge master
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
(ns frontend.worker.platform
|
||||
"Platform adapter contract for db-worker runtimes.")
|
||||
|
||||
(defn- normalize-missing-value
|
||||
[value]
|
||||
(if (identical? js/undefined value)
|
||||
nil
|
||||
value))
|
||||
|
||||
(def ^:private required-sections
|
||||
[:env :storage :kv :broadcast :websocket :crypto :timers :sqlite])
|
||||
|
||||
@@ -54,7 +60,8 @@
|
||||
(defn kv-get
|
||||
[platform k]
|
||||
(if-let [f (get-in platform [:kv :get])]
|
||||
(f k)
|
||||
(-> (f k)
|
||||
(.then normalize-missing-value))
|
||||
(throw (ex-info "platform kv/get missing" {:key k}))))
|
||||
|
||||
(defn kv-set!
|
||||
@@ -108,7 +115,8 @@
|
||||
(defn read-secret-text
|
||||
[platform key]
|
||||
(if-let [f (get-in platform [:crypto :read-secret-text])]
|
||||
(f key)
|
||||
(-> (f key)
|
||||
(.then normalize-missing-value))
|
||||
(throw (ex-info "platform crypto/read-secret-text missing" {:key key}))))
|
||||
|
||||
(defn delete-secret-text!
|
||||
|
||||
@@ -53,18 +53,39 @@
|
||||
(and (= :node runtime')
|
||||
(= :electron owner-source)))))
|
||||
|
||||
(defn- missing-e2ee-password-ex
|
||||
[data]
|
||||
(ex-info "missing-e2ee-password"
|
||||
(merge {:code :db-sync/missing-e2ee-password
|
||||
:field :e2ee-password}
|
||||
data)))
|
||||
|
||||
(defn- fail-missing-e2ee-password!
|
||||
[data]
|
||||
(fail-fast :db-sync/missing-e2ee-password
|
||||
(merge {:field :e2ee-password}
|
||||
(merge {:code :db-sync/missing-e2ee-password
|
||||
:field :e2ee-password}
|
||||
data)))
|
||||
|
||||
(defn- throw-missing-e2ee-password!
|
||||
[data]
|
||||
(throw (missing-e2ee-password-ex data)))
|
||||
|
||||
(defn- ensure-refresh-token!
|
||||
[refresh-token]
|
||||
(when-not (seq refresh-token)
|
||||
(fail-missing-e2ee-password! {:reason :missing-refresh-token
|
||||
:hint "Run logseq login first."})))
|
||||
|
||||
(defn- missing-persisted-password-error?
|
||||
[error]
|
||||
(let [data (ex-data error)]
|
||||
(and (contains? #{:db-sync/missing-e2ee-password
|
||||
:missing-e2ee-password}
|
||||
(or (:code data)
|
||||
(some-> error ex-message keyword)))
|
||||
(= :missing-persisted-password (:reason data)))))
|
||||
|
||||
(defn- parse-auth-file
|
||||
[text]
|
||||
(when (seq text)
|
||||
@@ -89,7 +110,10 @@
|
||||
(defn- <save-e2ee-password
|
||||
[password]
|
||||
(p/let [platform' (platform/current)
|
||||
refresh-token (<read-refresh-token-from-auth-file platform')
|
||||
refresh-token (if (browser-runtime? platform')
|
||||
(:auth/refresh-token @worker-state/*state)
|
||||
(<read-refresh-token-from-auth-file platform'))
|
||||
_ (ensure-refresh-token! refresh-token)
|
||||
result (crypt/<encrypt-text-by-text-password refresh-token password)
|
||||
text (ldb/write-transit-str result)]
|
||||
(if (browser-runtime? platform')
|
||||
@@ -113,8 +137,8 @@
|
||||
(p/catch (fn [_]
|
||||
nil))))]
|
||||
(when-not (seq text)
|
||||
(fail-missing-e2ee-password! {:reason :missing-persisted-password
|
||||
:hint "Provide --e2ee-password to persist it."}))
|
||||
(throw-missing-e2ee-password! {:reason :missing-persisted-password
|
||||
:hint "Provide --e2ee-password to persist it."}))
|
||||
(let [data (try
|
||||
(ldb/read-transit-str text)
|
||||
(catch :default _
|
||||
@@ -380,11 +404,13 @@
|
||||
(p/let [encrypted-private-key (ldb/read-transit-str encrypted-private-key-str)]
|
||||
(-> (<decrypt-in-headless encrypted-private-key)
|
||||
(p/catch (fn [headless-error]
|
||||
(if (interactive-runtime?)
|
||||
(if-not (interactive-runtime?)
|
||||
(p/rejected headless-error)
|
||||
(-> (<decrypt-with-ui-request encrypted-private-key)
|
||||
(p/catch (fn [_ui-error]
|
||||
(p/rejected headless-error))))
|
||||
(p/rejected headless-error))))))))
|
||||
(p/catch (fn [ui-error]
|
||||
(if (missing-persisted-password-error? headless-error)
|
||||
(p/rejected ui-error)
|
||||
(p/rejected headless-error))))))))))))
|
||||
|
||||
(defn- <import-public-key
|
||||
[public-key-str]
|
||||
|
||||
28
src/test/frontend/worker/platform_test.cljs
Normal file
28
src/test/frontend/worker/platform_test.cljs
Normal file
@@ -0,0 +1,28 @@
|
||||
(ns frontend.worker.platform-test
|
||||
(:require [cljs.test :refer [async deftest is]]
|
||||
[frontend.worker.platform :as platform]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(deftest kv-get-normalizes-undefined-to-nil-test
|
||||
(async done
|
||||
(-> (platform/kv-get {:kv {:get (fn [_k]
|
||||
(p/resolved js/undefined))}}
|
||||
"key")
|
||||
(p/then (fn [value]
|
||||
(is (nil? value))
|
||||
(is (not (identical? js/undefined value)))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally done))))
|
||||
|
||||
(deftest read-secret-text-normalizes-undefined-to-nil-test
|
||||
(async done
|
||||
(-> (platform/read-secret-text {:crypto {:read-secret-text (fn [_key]
|
||||
(p/resolved js/undefined))}}
|
||||
"secret")
|
||||
(p/then (fn [value]
|
||||
(is (nil? value))
|
||||
(is (not (identical? js/undefined value)))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally done))))
|
||||
@@ -99,10 +99,12 @@
|
||||
(deftest save-e2ee-password-uses-secret-storage-in-browser-runtime-test
|
||||
(async done
|
||||
(let [platform-map {:env {:runtime :browser}}
|
||||
state-prev @worker-state/*state
|
||||
secret-calls (atom [])
|
||||
file-calls (atom [])
|
||||
auth-read-calls (atom [])
|
||||
encrypt-calls (atom [])]
|
||||
(reset! worker-state/*state (assoc state-prev :auth/refresh-token "refresh-from-state"))
|
||||
(-> (p/with-redefs [crypt/<encrypt-text-by-text-password (fn [refresh-token password]
|
||||
(swap! encrypt-calls conj [refresh-token password])
|
||||
{:cipher "payload"})
|
||||
@@ -123,9 +125,8 @@
|
||||
(p/resolved nil))]
|
||||
(#'sync-crypt/<save-e2ee-password "password"))
|
||||
(p/then (fn [_]
|
||||
(is (= 1 (count @auth-read-calls)))
|
||||
(is (= "~/logseq/auth.json" (:path (first @auth-read-calls))))
|
||||
(is (= [["refresh-from-auth-file" "password"]] @encrypt-calls))
|
||||
(is (empty? @auth-read-calls))
|
||||
(is (= [["refresh-from-state" "password"]] @encrypt-calls))
|
||||
(is (= 1 (count @secret-calls)))
|
||||
(is (= platform-map (:platform (first @secret-calls))))
|
||||
(is (= "logseq-encrypted-password" (:key (first @secret-calls))))
|
||||
@@ -133,7 +134,9 @@
|
||||
(is (empty? @file-calls))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally done)))))
|
||||
(p/finally (fn []
|
||||
(reset! worker-state/*state state-prev)
|
||||
(done)))))))
|
||||
|
||||
(deftest save-e2ee-password-uses-file-storage-in-node-runtime-test
|
||||
(async done
|
||||
@@ -352,6 +355,46 @@
|
||||
(reset! worker-state/*state old-state)
|
||||
(done)))))))
|
||||
|
||||
(deftest decrypt-private-key-browser-fallback-does-not-log-missing-persisted-password-test
|
||||
(async done
|
||||
(let [old-state @worker-state/*state
|
||||
fail-calls (atom [])
|
||||
decrypt-calls (atom [])
|
||||
save-calls (atom [])]
|
||||
(reset! worker-state/*state (assoc old-state :auth/refresh-token "refresh-token"))
|
||||
(-> (p/with-redefs [platform/current (fn [] {:env {:runtime :browser}})
|
||||
platform/read-secret-text (fn [_platform' _key]
|
||||
(p/resolved nil))
|
||||
platform/read-text! (fn [_platform' _path]
|
||||
(p/rejected (ex-info "should-not-read-browser-file" {})))
|
||||
ui-request/<request (fn [_action payload _opts]
|
||||
(is (= {:reason :decrypt-user-rsa-private-key} payload))
|
||||
(p/resolved {:password "ui-password"}))
|
||||
sync-crypt/fail-missing-e2ee-password! (fn [data]
|
||||
(swap! fail-calls conj data)
|
||||
(throw (ex-info "missing-e2ee-password" data)))
|
||||
ldb/read-transit-str (fn [_] :encrypted-private-key)
|
||||
crypt/<decrypt-private-key (fn [password encrypted-private-key]
|
||||
(swap! decrypt-calls conj [password encrypted-private-key])
|
||||
(p/resolved :private-key))
|
||||
crypt/<encrypt-text-by-text-password (fn [refresh-token password]
|
||||
(swap! save-calls conj [:encrypt refresh-token password])
|
||||
{:cipher "password-payload"})
|
||||
platform/save-secret-text! (fn [_platform' key text]
|
||||
(swap! save-calls conj [:save key text])
|
||||
(p/resolved nil))]
|
||||
(#'sync-crypt/<decrypt-private-key "encrypted-private-key-str"))
|
||||
(p/then (fn [private-key]
|
||||
(is (= :private-key private-key))
|
||||
(is (= [["ui-password" :encrypted-private-key]] @decrypt-calls))
|
||||
(is (= 2 (count @save-calls)))
|
||||
(is (empty? @fail-calls))))
|
||||
(p/catch (fn [e]
|
||||
(is false (str e))))
|
||||
(p/finally (fn []
|
||||
(reset! worker-state/*state old-state)
|
||||
(done)))))))
|
||||
|
||||
(deftest ensure-graph-aes-key-uses-platform-kv-adapters-test
|
||||
(async done
|
||||
(let [fetch-prev js/fetch
|
||||
|
||||
Reference in New Issue
Block a user