039-worker-platform-abstraction-cleanup.md, rebase master fix (2)

This commit is contained in:
Gabriel Horner
2026-03-05 08:43:55 -05:00
committed by rcmerci
parent 7da6e97962
commit 7d4a241e6b
6 changed files with 406 additions and 10 deletions

View File

@@ -8,6 +8,7 @@
[frontend.common.crypt :as crypt]
[frontend.worker-common.util :as worker-util]
[frontend.worker.handler.page :as worker-page]
[frontend.worker.platform :as platform]
[frontend.worker.shared-service :as shared-service]
[frontend.worker.state :as worker-state]
[frontend.worker.sync.client-op :as client-op]
@@ -1783,7 +1784,8 @@
(stop-client! client))
;; use cache token for faster websocket connection
(when-let [token' (or token (auth-token))]
(let [ws (js/WebSocket. (append-token url token'))
(let [ws (platform/websocket-connect (platform/current)
(append-token url token'))
updated (assoc client :ws ws)]
(attach-ws-handlers! repo updated ws url)
(set! (.-onopen ws)

View File

@@ -3,9 +3,9 @@
(:require ["/frontend/idbkv" :as idb-keyval]
[clojure.string :as string]
[frontend.common.crypt :as crypt]
[frontend.common.file.opfs :as opfs]
[frontend.common.thread-api :refer [def-thread-api]]
[frontend.worker-common.util :as worker-util]
[frontend.worker.platform :as platform]
[frontend.worker.state :as worker-state]
[frontend.worker.sync.const :as sync-const]
[lambdaisland.glogi :as log]
@@ -48,14 +48,14 @@
nil)
(p/catch (fn [e]
(log/error :native-save-e2ee-password {:error e})
(opfs/<write-text! e2ee-password-file text))))
(opfs/<write-text! e2ee-password-file text))))
(platform/write-text! (platform/current) e2ee-password-file text))))
(platform/write-text! (platform/current) e2ee-password-file text))))
(defn- <read-e2ee-password
[refresh-token]
(p/let [text (if (native-worker?)
(<native-read-password-text)
(opfs/<read-text! e2ee-password-file))
(platform/read-text! (platform/current) e2ee-password-file))
data (ldb/read-transit-str text)
password (crypt/<decrypt-text-by-text-password refresh-token data)]
password))
@@ -149,14 +149,14 @@
(defn- <get-item
[k]
(assert (and k @e2ee-store))
(p/let [r (idb-keyval/get k @e2ee-store)]
(assert k)
(p/let [r (platform/kv-get (platform/current) k)]
(some-> r (js->clj :keywordize-keys true))))
(defn- <set-item!
[k value]
(assert (and k @e2ee-store))
(idb-keyval/set k value @e2ee-store))
(assert k)
(platform/kv-set! (platform/current) k value))
(defn- <clear-item!
[k]

View File

@@ -3,6 +3,7 @@
[datascript.core :as d]
[frontend.common.crypt :as crypt]
[frontend.worker-common.util :as worker-util]
[frontend.worker.platform :as platform]
[frontend.worker.shared-service :as shared-service]
[frontend.worker.state :as worker-state]
[frontend.worker.sync :as db-sync]
@@ -284,6 +285,32 @@
(reset! db-sync/*repo->latest-remote-tx latest-prev)
(done))))))))))
(deftest connect-uses-platform-websocket-adapter-test
(let [ws-ctor-prev js/WebSocket
platform-map {:runtime :test}
ws-calls (atom [])
attach-calls (atom [])]
(set! js/WebSocket (js* "(function(_url){ this.readyState = 1; })"))
(try
(with-redefs [worker-state/get-id-token (fn [] "token-123")
platform/current (fn [] platform-map)
platform/websocket-connect (fn [platform' url]
(swap! ws-calls conj {:platform platform' :url url})
(js-obj))
db-sync/attach-ws-handlers! (fn [repo _client ws url]
(swap! attach-calls conj {:repo repo :ws ws :url url}))]
(let [connected (#'db-sync/connect! test-repo {:repo test-repo} "wss://example.com/sync/graph-1")
ws (:ws connected)]
(is (= [{:platform platform-map
:url "wss://example.com/sync/graph-1?token=token-123"}]
@ws-calls))
(is (= [{:repo test-repo
:ws ws
:url "wss://example.com/sync/graph-1"}]
@attach-calls))))
(finally
(set! js/WebSocket ws-ctor-prev)))))
(deftest reaction-add-enqueues-pending-sync-tx-test
(testing "adding a reaction should enqueue tx for db-sync"
(let [{:keys [conn client-ops-conn parent]} (setup-parent-child)]

View File

@@ -1,6 +1,12 @@
(ns frontend.worker.sync.crypt-test
(:require [cljs.test :refer [deftest is async]]
["/frontend/idbkv" :as idb-keyval]
[clojure.string :as string]
[frontend.common.crypt :as crypt]
[frontend.common.file.opfs :as opfs]
[frontend.worker-common.util :as worker-util]
[frontend.worker.platform :as platform]
[frontend.worker.state :as worker-state]
[frontend.worker.sync.crypt :as sync-crypt]
[logseq.db :as ldb]
[promesa.core :as p]))
@@ -10,6 +16,154 @@
(p/let [encrypted (crypt/<encrypt-text aes-key (ldb/write-transit-str value))]
(ldb/write-transit-str encrypted)))
(deftest save-e2ee-password-uses-platform-write-text-when-not-native-test
(async done
(let [platform-map {:runtime :test}
write-calls (atom [])]
(-> (p/with-redefs [sync-crypt/native-worker? (fn [] false)
crypt/<encrypt-text-by-text-password (fn [_refresh-token _password]
{:cipher "payload"})
platform/current (fn [] platform-map)
platform/write-text! (fn [platform' path text]
(swap! write-calls conj {:platform platform'
:path path
:text text})
nil)
opfs/<write-text! (fn [_path _text]
nil)]
(#'sync-crypt/<save-e2ee-password "refresh-token" "password"))
(p/then (fn [_]
(is (= 1 (count @write-calls)))
(is (= platform-map (:platform (first @write-calls))))
(is (= "e2ee-password" (:path (first @write-calls))))))
(p/catch (fn [e]
(is false (str e))))
(p/finally done)))))
(deftest read-e2ee-password-uses-platform-read-text-when-not-native-test
(async done
(let [platform-map {:runtime :test}
read-calls (atom [])]
(-> (p/with-redefs [sync-crypt/native-worker? (fn [] false)
platform/current (fn [] platform-map)
platform/read-text! (fn [platform' path]
(swap! read-calls conj {:platform platform'
:path path})
(ldb/write-transit-str {:cipher "payload"}))
opfs/<read-text! (fn [_path]
(ldb/write-transit-str {:cipher "payload"}))
crypt/<decrypt-text-by-text-password (fn [_refresh-token _data]
"decrypted-password")]
(#'sync-crypt/<read-e2ee-password "refresh-token"))
(p/then (fn [password]
(is (= "decrypted-password" password))
(is (= 1 (count @read-calls)))
(is (= platform-map (:platform (first @read-calls))))
(is (= "e2ee-password" (:path (first @read-calls))))))
(p/catch (fn [e]
(is false (str e))))
(p/finally done)))))
(deftest save-e2ee-password-native-fallback-uses-platform-write-text-test
(async done
(let [platform-map {:runtime :test}
write-calls (atom [])]
(-> (p/with-redefs [sync-crypt/native-worker? (fn [] true)
sync-crypt/<native-save-password-text! (fn [_text]
(p/rejected (ex-info "native write failed" {})))
crypt/<encrypt-text-by-text-password (fn [_refresh-token _password]
{:cipher "payload"})
platform/current (fn [] platform-map)
platform/write-text! (fn [platform' path text]
(swap! write-calls conj {:platform platform'
:path path
:text text})
nil)
opfs/<write-text! (fn [_path _text]
nil)]
(#'sync-crypt/<save-e2ee-password "refresh-token" "password"))
(p/then (fn [_]
(is (= 1 (count @write-calls)))
(is (= platform-map (:platform (first @write-calls))))
(is (= "e2ee-password" (:path (first @write-calls))))))
(p/catch (fn [e]
(is false (str e))))
(p/finally done)))))
(deftest ensure-graph-aes-key-uses-platform-kv-adapters-test
(async done
(let [fetch-prev js/fetch
graph-id (str (random-uuid))
expected-key (str "rtc-encrypted-aes-key###" graph-id)
platform-map {:runtime :test}
current-calls (atom 0)
kv-get-calls (atom [])
kv-set-calls (atom [])]
(set! js/fetch
(fn [url _opts]
(cond
(string/includes? url "/e2ee/user-keys")
(js/Promise.resolve
#js {:ok true
:text (fn []
(js/Promise.resolve
"{\"public-key\":\"public-key\",\"encrypted-private-key\":\"encrypted-private-key\"}"))})
(string/includes? url (str "/e2ee/graphs/" graph-id "/aes-key"))
(js/Promise.resolve
#js {:ok true
:text (fn []
(js/Promise.resolve
"{\"encrypted-aes-key\":\"remote-encrypted\"}"))})
:else
(js/Promise.resolve
#js {:ok false
:status 404
:text (fn [] (js/Promise.resolve "{\"message\":\"not-found\"}"))}))))
(-> (p/with-redefs [sync-crypt/graph-e2ee? (fn [_repo] true)
sync-crypt/e2ee-base (fn [] "https://example.com")
worker-state/get-id-token (fn [] "token")
worker-util/parse-jwt (fn [_] {:sub "user-1"})
worker-state/<invoke-main-thread (fn [_type _payload]
(p/resolved :exported-private-key))
crypt/<import-private-key (fn [_]
(p/resolved :private-key))
crypt/<import-public-key (fn [_]
(p/resolved :public-key))
crypt/<decrypt-aes-key (fn [_private-key encrypted]
(p/resolved (str "aes:" encrypted)))
ldb/read-transit-str (fn [value] value)
platform/current (fn []
(swap! current-calls inc)
platform-map)
platform/kv-get (fn [platform' k]
(swap! kv-get-calls conj {:platform platform' :key k})
(p/resolved nil))
platform/kv-set! (fn [platform' k value]
(swap! kv-set-calls conj {:platform platform' :key k :value value})
(p/resolved nil))
idb-keyval/get (fn [_k _store]
(p/resolved nil))
idb-keyval/set (fn [_k _v _store]
(p/resolved nil))]
(sync-crypt/<ensure-graph-aes-key "repo-1" graph-id))
(p/then (fn [aes-key]
(is (= "aes:remote-encrypted" aes-key))
(is (= [{:platform platform-map
:key expected-key}]
@kv-get-calls))
(is (= [{:platform platform-map
:key expected-key
:value "remote-encrypted"}]
@kv-set-calls))
(is (pos? @current-calls))))
(p/catch (fn [e]
(is false (str e))))
(p/finally (fn []
(set! js/fetch fetch-prev)
(done)))))))
;; bb dev:test -v frontend.worker.sync.crypt-test works, however bb dev:lint-and-test failed
(deftest ^:fix-me decrypt-snapshot-rows-test
(async done