feat(rtc,e2ee): basic e2ee-password ui

This commit is contained in:
rcmerci
2025-11-01 20:39:55 +08:00
committed by Tienson Qin
parent 9c37377b48
commit d1d1ca30ed
7 changed files with 123 additions and 10 deletions

View File

@@ -35,6 +35,20 @@
true
#js ["encrypt"]))
(defn <export-private-key
[private-key]
(assert (instance? js/CryptoKey private-key))
(p/let [exported (.exportKey subtle "pkcs8" private-key)]
(js/Uint8Array. exported)))
(defn <import-private-key
[exported-private-key]
(assert (instance? js/Uint8Array exported-private-key))
(.importKey subtle "pkcs8" exported-private-key
#js {:name "RSA-OAEP" :hash "SHA-256"}
true
#js ["decrypt"]))
(comment
(->
(p/let [kp (<generate-rsa-key-pair)

View File

@@ -0,0 +1,53 @@
(ns frontend.components.e2ee
(:require [frontend.common.crypt :as crypt]
[logseq.shui.hooks :as hooks]
[logseq.shui.ui :as shui]
[promesa.core :as p]
[rum.core :as rum]))
(rum/defc e2ee-request-new-password
[password-promise]
(let [[password set-password!] (hooks/use-state "")]
[:div.e2ee-password-modal-overlay
[:div.e2ee-password-modal-content
[:h3 "Enter new E2EE Password"]
[:input {:type "password"
:value password
:on-change (fn [e] (set-password! (-> e .-target .-value)))}]
(shui/button
{:on-click (fn []
(p/resolve! password-promise password)
(shui/dialog-close!))}
"OK")
(shui/button
{:on-click (fn []
(p/reject! password-promise :cancelled)
(shui/dialog-close!))}
"Cancel")]]))
(rum/defc e2ee-password-to-decrypt-private-key
[encrypted-private-key private-key-promise]
(let [[password set-password!] (hooks/use-state "")
[decrypt-fail? set-decrypt-fail] (hooks/use-state false)]
[:div.e2ee-password-modal-overlay
[:div.e2ee-password-modal-content
[:h3 "Enter E2EE Password"]
(when decrypt-fail? [:p "Wrong Password"])
[:input {:type "password"
:value password
:on-change (fn [e] (set-password! (-> e .-target .-value)))}]
(shui/button
{:on-click (fn []
(->
(p/let [private-key (crypt/<decrypt-private-key password encrypted-private-key)]
(p/resolve! private-key-promise private-key)
(shui/dialog-close!))
(p/catch (fn [e]
(when (= "decrypt-private-key" (ex-message e))
(set-decrypt-fail true))))))}
"OK")
(shui/button
{:on-click (fn []
(p/reject! private-key-promise :cancelled)
(shui/dialog-close!))}
"Cancel")]]))

View File

@@ -17,9 +17,10 @@
[frontend.db.restore :as db-restore]
[frontend.error :as error]
[frontend.handler.command-palette :as command-palette]
[frontend.handler.crypt]
[frontend.handler.db-based.vector-search-flows :as vector-search-flows]
[frontend.handler.e2ee]
[frontend.handler.events :as events]
[frontend.handler.events.rtc]
[frontend.handler.events.ui]
[frontend.handler.file-based.events]
[frontend.handler.file-based.file :as file-handler]

View File

@@ -1,6 +0,0 @@
(ns frontend.handler.crypt
(:require [frontend.common.thread-api :refer [def-thread-api]]))
(def-thread-api :thread-api/request-e2ee-password
[]
{:password "test-password"})

View File

@@ -0,0 +1,26 @@
(ns frontend.handler.e2ee
(:require [frontend.common.crypt :as crypt]
[frontend.common.thread-api :refer [def-thread-api]]
[frontend.state :as state]
[lambdaisland.glogi :as log]
[promesa.core :as p]))
(def-thread-api :thread-api/request-e2ee-password
[]
(p/let [password-promise (state/pub-event! [:rtc/request-e2ee-password])
password password-promise]
{:password password}))
(defn- <decrypt-user-e2ee-private-key
[encrypted-private-key]
(->
(p/let [private-key-promise (state/pub-event! [:rtc/decrypt-user-e2ee-private-key encrypted-private-key])
private-key private-key-promise]
(crypt/<export-private-key private-key))
(p/catch (fn [e]
(log/error :<decrypt-user-e2ee-private-key e)
e))))
(def-thread-api :thread-api/decrypt-user-e2ee-private-key
[encrypted-private-key]
(<decrypt-user-e2ee-private-key encrypted-private-key))

View File

@@ -0,0 +1,22 @@
(ns frontend.handler.events.rtc
"RTC events"
(:require [frontend.components.e2ee :as e2ee]
[frontend.handler.events :as events]
[logseq.shui.ui :as shui]
[promesa.core :as p]))
(defmethod events/handle :rtc/decrypt-user-e2ee-private-key [[_ encrypted-private-key]]
(let [private-key-promise (p/deferred)]
(shui/dialog-close-all!)
(shui/dialog-open!
#(e2ee/e2ee-password-to-decrypt-private-key encrypted-private-key private-key-promise)
{:close-btn? false})
private-key-promise))
(defmethod events/handle :rtc/request-e2ee-password [[_]]
(let [password-promise (p/deferred)]
(shui/dialog-close-all!)
(shui/dialog-open!
#(e2ee/e2ee-request-new-password password-promise)
{:close-btn? false})
password-promise))

View File

@@ -121,10 +121,13 @@
(defn task--get-rsa-key-pair
[get-ws-create-task user-uuid]
(m/sp
(let [{:keys [password]} (c.m/<? (worker-state/<invoke-main-thread :thread-api/request-e2ee-password))
{:keys [public-key encrypted-private-key]}
(let [{:keys [public-key encrypted-private-key]}
(m/? (task--fetch-user-rsa-key-pair get-ws-create-task user-uuid))
private-key (c.m/<? (crypt/<decrypt-private-key password encrypted-private-key))]
_ (prn :xxxxx1)
exported-private-key (c.m/<? (worker-state/<invoke-main-thread
:thread-api/decrypt-user-e2ee-private-key encrypted-private-key))
_ (prn :xxxxx2)
private-key (c.m/<? (crypt/<import-private-key exported-private-key))]
{:public-key public-key
:private-key private-key})))