Browse Source

feat(encryption): store :db/encrypted-secret in metadata.edn

Tienson Qin 5 years ago
parent
commit
3a08f8bf72

+ 39 - 4
src/main/frontend/components/encryption.cljs

@@ -5,7 +5,8 @@
             [frontend.context.i18n :as i18n]
             [frontend.db.utils :as db-utils]
             [clojure.string :as string]
-            [frontend.state :as state]))
+            [frontend.state :as state]
+            [frontend.handler.metadata :as metadata-handler]))
 
 (rum/defcs encryption-dialog-inner <
   (rum/local false ::reveal-secret-phrase?)
@@ -44,11 +45,46 @@
            :on-click close-fn}
           (t :close)]]]])))
 
-(defn encryptioin-dialog
+(defn encryption-dialog
   [repo-url]
   (fn [close-fn]
     (encryption-dialog-inner repo-url close-fn)))
 
+(rum/defcs input-password-inner <
+  (rum/local "" ::password)
+  [state repo-url close-fn]
+  (rum/with-context [[t] i18n/*tongue-context*]
+    (let [password (get state ::password)]
+      [:div
+       [:div.sm:flex.sm:items-start
+        [:div.mt-3.text-center.sm:mt-0.sm:text-left
+         [:h3#modal-headline.text-lg.leading-6.font-medium.text-gray-900
+          "Enter a password"]]]
+
+       [:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
+        {:auto-focus true
+         :style {:color "#000"}
+         :on-change (fn [e]
+                      (reset! password (util/evalue e)))}]
+
+       [:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
+        [:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
+         [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
+          {:type "button"
+           :on-click (fn []
+                       (let [value @password]
+                         (when-not (string/blank? value)
+                           (when-let [mnemonic (e/generate-mnemonic-and-save! repo-url)]
+                             (let [db-encrypted-secret (e/encrypt-with-passphrase value mnemonic)]
+                               (metadata-handler/set-db-encrypted-secret! db-encrypted-secret)))
+                           (close-fn true))))}
+          "Submit"]]]])))
+
+(defn input-password
+  [repo-url close-fn]
+  (fn [_close-fn]
+    (input-password-inner repo-url close-fn)))
+
 (rum/defcs encryption-setup-dialog-inner
   [state repo-url close-fn]
   (rum/with-context [[t] i18n/*tongue-context*]
@@ -63,8 +99,7 @@
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
         {:type "button"
          :on-click (fn []
-                     (e/generate-mnemonic-and-save! repo-url)
-                     (close-fn true))}
+                     (state/set-modal! (input-password repo-url close-fn)))}
         (t :yes)]]
       [:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
        [:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5

+ 1 - 1
src/main/frontend/components/repo.cljs

@@ -65,7 +65,7 @@
                 (when (e/encrypted-db? url)
                   [:a.control {:title "Show encryption information about this graph"
                                :on-click (fn []
-                                           (state/set-modal! (encryption/encryptioin-dialog url)))}
+                                           (state/set-modal! (encryption/encryption-dialog url)))}
                    "🔐"])
                 [:a.control.ml-4 {:title (if local?
                                            "Sync with the local directory"

+ 4 - 2
src/main/frontend/encrypt.cljs

@@ -38,7 +38,8 @@
   [repo-url]
   (when-not (get-mnemonic repo-url)
     (let [mnemonic (generate-mnemonic)]
-      (save-mnemonic! repo-url mnemonic))))
+      (save-mnemonic! repo-url mnemonic)
+      mnemonic)))
 
 (defn- derive-key-from-mnemonic
   [mnemonic]
@@ -89,8 +90,9 @@
         encrypted (rage/encrypt_with_user_passphrase passphrase content true)]
     (utf8/decode encrypted)))
 
+;; TODO: What if decryption failed
 (defn decrypt-with-passphrase
   [passphrase content]
   (let [content (utf8/encode content)
         decrypted (rage/decrypt_with_user_passphrase passphrase content)]
-    (utf8/decode decrypted)))
+    (utf8/decode decrypted)))

+ 3 - 2
src/main/frontend/fs.cljs

@@ -65,8 +65,9 @@
 (defn write-file!
   [repo dir path content opts]
   (when content
-    (let [metadata? (string/ends-with? path config/metadata-file)
-          content (if metadata? content (encrypt/encrypt content))]
+    (let [metadata-or-css? (or (string/ends-with? path config/metadata-file)
+                               (string/ends-with? path config/custom-css-file))
+          content (if metadata-or-css? content (encrypt/encrypt content))]
       (->
        (do
          (protocol/write-file! (get-fs dir) repo dir path content opts)

+ 2 - 2
src/main/frontend/handler/config.cljs

@@ -1,6 +1,6 @@
 (ns frontend.handler.config
   (:require [frontend.state :as state]
-            [frontend.handler.repo :as repo-handler]
+            [frontend.handler.file :as file-handler]
             [borkdude.rewrite-edn :as rewrite]
             [frontend.config :as config]
             [frontend.db :as db]
@@ -21,7 +21,7 @@
               new-config (rewrite/assoc-in config ks v)]
           (state/set-config! repo new-config)
           (let [new-content (str new-config)]
-            (repo-handler/set-config-content! repo path new-content)))))))
+            (file-handler/set-file-content! repo path new-content)))))))
 
 (defn toggle-ui-show-brackets! []
   (let [show-brackets? (state/show-brackets?)]

+ 17 - 0
src/main/frontend/handler/file.cljs

@@ -195,6 +195,11 @@
        (println "Write file failed, path: " path ", content: " content)
        (js/console.error error)))))
 
+(defn set-file-content!
+  [repo path new-content]
+  (alter-file repo path new-content {:reset? false
+                                     :re-render-root? false}))
+
 (defn create!
   ([path]
    (create! path ""))
@@ -322,3 +327,15 @@
           directories (map (fn [repo] (config/get-repo-dir (:url repo))) repos)]
       (doseq [dir directories]
         (fs/watch-dir! dir)))))
+
+(defn create-metadata-file
+  [repo-url encrypted?]
+  (let [repo-dir (config/get-repo-dir repo-url)
+        path (str config/app-name "/" config/metadata-file)
+        file-path (str "/" path)
+        default-content (if encrypted? "{:db/encrypted? true}" "{}")]
+    (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" config/app-name))
+            file-exists? (fs/create-if-not-exists repo-url repo-dir file-path default-content)]
+      (when-not file-exists?
+        (reset-file! repo-url path default-content)
+        (git-handler/git-add repo-url path)))))

+ 37 - 0
src/main/frontend/handler/metadata.cljs

@@ -0,0 +1,37 @@
+(ns frontend.handler.metadata
+  (:require [frontend.state :as state]
+            [frontend.handler.file :as file-handler]
+            [cljs.reader :as reader]
+            [frontend.config :as config]
+            [frontend.db :as db]
+            [clojure.string :as string]
+            [promesa.core :as p]))
+
+(def default-metadata-str "{}")
+
+(defn set-metadata!
+  [k v]
+  (when-let [repo (state/get-current-repo)]
+    (let [encrypted? (= k :db/encrypted-secret)
+          path (config/get-metadata-path)
+          file-content (db/get-file-no-sub path)]
+      (p/let [_ (file-handler/create-metadata-file repo false)]
+        (let [metadata-str (or file-content default-metadata-str)
+              metadata (try
+                         (reader/read-string metadata-str)
+                         (catch js/Error e
+                           (println "Parsing metadata.edn failed: ")
+                           (js/console.dir e)
+                           {}))
+              ks (if (vector? k) k [k])
+              new-metadata (assoc-in metadata ks v)
+              new-metadata (if encrypted?
+                             (assoc new-metadata :db/encrypted? true)
+                             new-metadata)
+              new-content (pr-str new-metadata)]
+          (file-handler/set-file-content! repo path new-content))))))
+
+(defn set-db-encrypted-secret!
+  [encrypted-secret]
+  (when-not (string/blank? encrypted-secret)
+    (set-metadata! :db/encrypted-secret encrypted-secret)))

+ 4 - 20
src/main/frontend/handler/repo.cljs

@@ -28,6 +28,7 @@
             [frontend.encrypt :as encrypt]
             [goog.dom :as gdom]
             [goog.object :as gobj]
+            ;; TODO: remove component dependency from handlers, we can use a core.async channel
             [frontend.components.encryption :as encryption]))
 
 ;; Project settings should be checked in two situations:
@@ -162,25 +163,13 @@
         (when (empty? (db/get-page-blocks-no-cache repo today-page))
           (create-today-journal-if-not-exists repo))))))
 
-(defn create-metadata-file
-  [repo-url encrypted?]
-  (spec/validate :repos/url repo-url)
-  (let [repo-dir (config/get-repo-dir repo-url)
-        path (str config/app-name "/" config/metadata-file)
-        file-path (str "/" path)
-        default-content (if encrypted? "{:db/encrypted? true}" "{}")]
-    (p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" config/app-name))
-            file-exists? (fs/create-if-not-exists repo-url repo-dir file-path default-content)]
-      (when-not file-exists?
-        (file-handler/reset-file! repo-url path default-content)
-        (git-handler/git-add repo-url path)))))
-
 (defn create-default-files!
   ([repo-url]
    (create-default-files! repo-url false))
   ([repo-url encrypted?]
    (spec/validate :repos/url repo-url)
-   (create-metadata-file repo-url encrypted?)
+   (file-handler/create-metadata-file repo-url encrypted?)
+   ;; TODO: move to frontend.handler.file
    (create-config-file-if-not-exists repo-url)
    (create-today-journal-if-not-exists repo-url)
    (create-contents-file repo-url)
@@ -574,14 +563,9 @@
          (git-handler/set-git-error! repo-url e)
          (show-install-error! repo-url (util/format "Failed to clone %s." repo-url)))))))
 
-(defn set-config-content!
-  [repo path new-content]
-  (file-handler/alter-file repo path new-content {:reset? false
-                                                  :re-render-root? false}))
-
 (defn remove-repo!
   [{:keys [id url] :as repo}]
-  (spec/validate :repos/repo repo)
+  ;; (spec/validate :repos/repo repo)
   (let [delete-db-f (fn []
                       (db/remove-conn! url)
                       (db/remove-db! url)