Browse Source

enhance(rtc,e2ee): init user rsa-pair in debug-ui

rcmerci 1 week ago
parent
commit
980bd9d112

+ 22 - 0
src/main/frontend/common/crypt.cljs

@@ -4,6 +4,28 @@
 
 (defonce subtle (.. js/crypto -subtle))
 
+(defn <export-public-key
+  [public-key]
+  (p/let [exported (.exportKey subtle "spki" public-key)]
+    (js/Uint8Array. exported)))
+
+(defn <import-public-key
+  [exported-public-key]
+  (.importKey subtle "spki" exported-public-key
+              #js {:name "RSA-OAEP" :hash "SHA-256"}
+              true
+              #js ["encrypt"]))
+
+(comment
+  (->
+   (p/let [kp (<generate-rsa-key-pair)
+           public-key (:publicKey kp)
+           exported-public-key (<export-public-key public-key)
+           public-key* (<import-public-key exported-public-key)
+           exported-public-key2 (<export-public-key public-key*)]
+     (prn (= (vec exported-public-key) (vec exported-public-key2))))
+   (p/catch (fn [e] (prn :e e)))))
+
 (defn <generate-rsa-key-pair
   "Generates a new RSA public/private key pair.
   Return

+ 18 - 56
src/main/frontend/db/rtc/debug_ui.cljs

@@ -8,6 +8,7 @@
             [frontend.state :as state]
             [frontend.ui :as ui]
             [frontend.util :as util]
+            [lambdaisland.glogi :as log]
             [logseq.db.frontend.schema :as db-schema]
             [logseq.shui.ui :as shui]
             [missionary.core :as m]
@@ -214,7 +215,7 @@
          :placeholder "repo name here"}]]]
 
      [:div.flex.my-2.items-center.gap-2
-      (ui/button (str "upload current repo")
+      (ui/button "upload current repo"
                  {:icon "upload"
                   :on-click (fn []
                               (let [repo (state/get-current-repo)
@@ -265,61 +266,22 @@
          (shui/button
           {:size :sm
            :on-click (fn [_]
-                       (p/let [graph-keys (state/<invoke-db-worker :thread-api/rtc-get-graph-keys (state/get-current-repo))
-                               devices (some->> (state/get-auth-id-token)
-                                                (state/<invoke-db-worker :thread-api/list-devices))]
-                         (swap! (get state ::keys-state) #(merge % graph-keys {:devices devices}))))}
-          (shui/tabler-icon "refresh") "keys-state")]
+                       (when-let [user-uuid (user/user-uuid)]
+                         (p/let [user-rsa-key-pair (state/<invoke-db-worker
+                                                    :thread-api/get-user-rsa-key-pair-from-indexeddb
+                                                    user-uuid)]
+                           (reset! *keys-state user-rsa-key-pair))))}
+          (shui/tabler-icon "refresh") "keys-state")
+         (shui/button
+          {:size :sm
+           :on-click (fn [_]
+                       (when-let [token (state/get-auth-id-token)]
+                         (p/let [r (state/<invoke-db-worker :thread-api/init-user-rsa-key-pair token (user/user-uuid))]
+                           (when (instance? ExceptionInfo r)
+                             (log/error :thread-api/init-user-rsa-key-pair r)))))}
+          (shui/tabler-icon "upload") "init upload user rsa-key-pair")]
         [:div.pb-4
          [:pre.select-text
-          (-> {:devices (:devices keys-state)
-               :graph-aes-key-jwk (:aes-key-jwk keys-state)}
+          (-> keys-state
               (fipp/pprint {:width 20})
-              with-out-str)]]
-        (shui/button
-         {:size :sm
-          :on-click (fn [_]
-                      (when-let [device-uuid (not-empty (:remove-device-device-uuid keys-state))]
-                        (when-let [token (state/get-auth-id-token)]
-                          (state/<invoke-db-worker :thread-api/remove-device token device-uuid))))}
-         "Remove device:")
-        [:input.form-input.my-2.py-1.w-32
-         {:on-change (fn [e] (swap! *keys-state assoc :remove-device-device-uuid (util/evalue e)))
-          :on-focus (fn [e] (let [v (.-value (.-target e))]
-                              (when (= v "device-uuid here")
-                                (set! (.-value (.-target e)) ""))))
-          :placeholder "device-uuid here"}]
-        (shui/button
-         {:size :sm
-          :on-click (fn [_]
-                      (when-let [device-uuid (not-empty (:remove-public-key-device-uuid keys-state))]
-                        (when-let [key-name (not-empty (:remove-public-key-key-name keys-state))]
-                          (when-let [token (state/get-auth-id-token)]
-                            (state/<invoke-db-worker :thread-api/remove-device-public-key token device-uuid key-name)))))}
-         "Remove public-key:")
-        [:input.form-input.my-2.py-1.w-32
-         {:on-change (fn [e] (swap! *keys-state assoc :remove-public-key-device-uuid (util/evalue e)))
-          :on-focus (fn [e] (let [v (.-value (.-target e))]
-                              (when (= v "device-uuid here")
-                                (set! (.-value (.-target e)) ""))))
-          :placeholder "device-uuid here"}]
-        [:input.form-input.my-2.py-1.w-32
-         {:on-change (fn [e] (swap! *keys-state assoc :remove-public-key-key-name (util/evalue e)))
-          :on-focus (fn [e] (let [v (.-value (.-target e))]
-                              (when (= v "key-name here")
-                                (set! (.-value (.-target e)) ""))))
-          :placeholder "key-name here"}]
-        (shui/button
-         {:size :sm
-          :on-click (fn [_]
-                      (when-let [token (state/get-auth-id-token)]
-                        (when-let [device-uuid (not-empty (:sync-private-key-device-uuid keys-state))]
-                          (state/<invoke-db-worker :thread-api/rtc-sync-current-graph-encrypted-aes-key
-                                                   token [(parse-uuid device-uuid)]))))}
-         "Sync CurrentGraph EncryptedAesKey")
-        [:input.form-input.my-2.py-1.w-32
-         {:on-change (fn [e] (swap! *keys-state assoc :sync-private-key-device-uuid (util/evalue e)))
-          :on-focus (fn [e] (let [v (.-value (.-target e))]
-                              (when (= v "device-uuid here")
-                                (set! (.-value (.-target e)) ""))))
-          :placeholder "device-uuid here"}]])]))
+              with-out-str)]]])]))

+ 28 - 10
src/main/frontend/worker/rtc/crypt.cljs

@@ -6,10 +6,13 @@
   (:require ["/frontend/idbkv" :as idb-keyval]
             [frontend.common.crypt :as crypt]
             [frontend.common.missionary :as c.m]
+            [frontend.common.thread-api :refer [def-thread-api]]
             [frontend.worker.rtc.ws-util :as ws-util]
             [frontend.worker.state :as worker-state]
+            [logseq.db :as ldb]
             [missionary.core :as m]
-            [promesa.core :as p]))
+            [promesa.core :as p])
+  (:import [missionary Cancelled]))
 
 (defonce ^:private store (delay (idb-keyval/newStore "localforage" "keyvaluepairs" 2)))
 
@@ -40,14 +43,15 @@
 
 (defn task--upload-user-rsa-key-pair
   "Uploads the user's RSA key pair to the server."
-  [token user-uuid public-key encrypted-private-key]
+  [get-ws-create-task user-uuid public-key encrypted-private-key]
   (m/sp
-    (let [{:keys [get-ws-create-task]} (ws-util/gen-get-ws-create-map--memoized (ws-util/get-ws-url token))
+    (let [exported-public-key-str (ldb/write-transit-str (c.m/<? (crypt/<export-public-key public-key)))
+          encrypted-private-key-str (ldb/write-transit-str encrypted-private-key)
           response (m/? (ws-util/send&recv get-ws-create-task
                                            {:action "upload-user-rsa-key-pair"
                                             :user-uuid user-uuid
-                                            :public-key public-key
-                                            :encrypted-private-key encrypted-private-key}))]
+                                            :public-key exported-public-key-str
+                                            :encrypted-private-key encrypted-private-key-str}))]
       (when (:ex-data response)
         (throw (ex-info (:ex-message response)
                         (assoc (:ex-data response) :type :rtc.exception/upload-user-rsa-key-pair-error)))))))
@@ -103,11 +107,6 @@
   []
   (m/sp (c.m/<? (crypt/<generate-aes-key))))
 
-(defn task--get-user-public-key
-  [get-ws-create-task user-uuid]
-  (m/sp
-    (:public-key (m/? (task--fetch-user-rsa-key-pair get-ws-create-task user-uuid)))))
-
 (defn task--get-rsa-key-pair
   [get-ws-create-task user-uuid]
   (m/sp
@@ -124,6 +123,25 @@
     (let [{:keys [_public-key private-key]} (m/? (task--get-rsa-key-pair get-ws-create-task user-uuid))]
       (m/? (task--fetch-graph-aes-key get-ws-create-task graph-uuid private-key)))))
 
+(def-thread-api :thread-api/get-user-rsa-key-pair-from-indexeddb
+  [user-uuid]
+  (<get-item (user-rsa-key-pair-idb-key user-uuid)))
+
+(def-thread-api :thread-api/init-user-rsa-key-pair
+  [token user-uuid]
+  (m/sp
+    (try
+      (let [{:keys [get-ws-create-task]} (ws-util/gen-get-ws-create-map--memoized (ws-util/get-ws-url token))]
+        (when-not (m/? (task--fetch-user-rsa-key-pair get-ws-create-task user-uuid))
+          (let [{:keys [publicKey privateKey]} (c.m/<? (crypt/<generate-rsa-key-pair))
+                password (c.m/<? (worker-state/<invoke-main-thread :thread-api/request-e2ee-password))
+                encrypted-private-key (c.m/<? (crypt/<encrypt-private-key password privateKey))]
+            (m/? (task--upload-user-rsa-key-pair get-ws-create-task user-uuid publicKey encrypted-private-key))
+            ;; fetch again
+            (m/? (task--fetch-user-rsa-key-pair get-ws-create-task user-uuid)))))
+      (catch Cancelled _)
+      (catch :default e e))))
+
 (comment
   (do
     (defn- array-buffers-equal?

+ 1 - 1
src/main/frontend/worker/rtc/full_upload_download_graph.cljs

@@ -152,7 +152,7 @@
                             worker-util/parse-jwt
                             :sub)
           public-key (when user-uuid
-                       (m/? (rtc-crypt/task--get-user-public-key get-ws-create-task user-uuid)))]
+                       (:public-key (m/? (rtc-crypt/task--fetch-user-rsa-key-pair get-ws-create-task user-uuid))))]
       (when-not public-key
         (throw (ex-info "user public-key not found" {:type :rtc.exception/not-found-user-rsa-key-pair
                                                      :user-uuid user-uuid})))