mirror of
https://github.com/unclebob/more-speech.git
synced 2024-09-30 10:30:56 +00:00
Migration 11 is ready. It password protects the private key. Data storage functions encode and decode the private key and password.
This commit is contained in:
parent
eed87443dc
commit
9a49498f8e
@ -1,13 +1,17 @@
|
|||||||
(ns more-speech.migrator-spec
|
(ns more-speech.migrator-spec
|
||||||
(:require [speclj.core :refer :all]
|
(:require [clojure.java.io :as io]
|
||||||
[more-speech.migrator :refer :all]
|
[more-speech.bech32 :as bech32]
|
||||||
[more-speech.config :as config]
|
[more-speech.config :as config]
|
||||||
[clojure.java.io :as io]
|
[more-speech.data-storage :as data-storage]
|
||||||
[more-speech.user-configuration :as user-configuration]
|
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.db.in-memory :as in-memory]
|
[more-speech.db.in-memory :as in-memory]
|
||||||
|
[more-speech.mem :as mem]
|
||||||
|
[more-speech.migrator :refer :all]
|
||||||
|
[more-speech.nostr.elliptic-signature :as es]
|
||||||
|
[more-speech.nostr.util :as util]
|
||||||
|
[more-speech.user-configuration :as user-configuration]
|
||||||
[more-speech.util.files :refer :all]
|
[more-speech.util.files :refer :all]
|
||||||
[more-speech.nostr.util :as util]))
|
[speclj.core :refer :all]))
|
||||||
|
|
||||||
(defn change-to-tmp-files []
|
(defn change-to-tmp-files []
|
||||||
(when (file-exists? "tmp")
|
(when (file-exists? "tmp")
|
||||||
@ -279,9 +283,9 @@
|
|||||||
renamed-dir (str @config/messages-directory ".migrated")]
|
renamed-dir (str @config/messages-directory ".migrated")]
|
||||||
(.mkdir (io/file "tmp/messages"))
|
(.mkdir (io/file "tmp/messages"))
|
||||||
(spit path1 [{:id 1 :content "c1"}
|
(spit path1 [{:id 1 :content "c1"}
|
||||||
{:id 2 :content "c2"}])
|
{:id 2 :content "c2"}])
|
||||||
(spit path2 [{:id 3 :content "c3"}
|
(spit path2 [{:id 3 :content "c3"}
|
||||||
{:id 4 :content "c4"}])
|
{:id 4 :content "c4"}])
|
||||||
(migration-10-load-events)
|
(migration-10-load-events)
|
||||||
(should= {:id 1 :content "c1"} (gateway/get-event @db 1))
|
(should= {:id 1 :content "c1"} (gateway/get-event @db 1))
|
||||||
(should= {:id 2 :content "c2"} (gateway/get-event @db 2))
|
(should= {:id 2 :content "c2"} (gateway/get-event @db 2))
|
||||||
@ -295,4 +299,89 @@
|
|||||||
(should (file-exists? (str renamed-dir f2 ".migrated")))
|
(should (file-exists? (str renamed-dir f2 ".migrated")))
|
||||||
(prn 'got-here)))
|
(prn 'got-here)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(context "migration 11 password protect private key"
|
||||||
|
(with db (in-memory/get-db))
|
||||||
|
(before-all (config/set-db! :in-memory))
|
||||||
|
(before (in-memory/clear-db @db)
|
||||||
|
(mem/clear-mem))
|
||||||
|
|
||||||
|
(it "password protects the keys file"
|
||||||
|
(let [bytes-private-key (util/make-private-key)
|
||||||
|
private-key (util/hexify (util/bytes->num bytes-private-key))]
|
||||||
|
(spit @config/keys-filename {:private-key private-key})
|
||||||
|
(migration-11-password-for-private-key)
|
||||||
|
(let [keys (read-string (slurp @config/keys-filename))
|
||||||
|
encrypted-private-key (:private-key keys)
|
||||||
|
decoded-private-key (util/xor-string "password" (bech32/address->str encrypted-private-key))]
|
||||||
|
(should= private-key decoded-private-key)
|
||||||
|
(should= "password" (bech32/address->str (:password keys))))))
|
||||||
|
|
||||||
|
(context "data storage changes"
|
||||||
|
(it "reads the keys with no password"
|
||||||
|
(let [bytes-private-key (util/make-private-key)
|
||||||
|
hex-private-key (util/hexify (util/bytes->num bytes-private-key))
|
||||||
|
bytes-public-key (es/get-pub-key bytes-private-key)
|
||||||
|
public-key (util/bytes->num bytes-public-key)
|
||||||
|
hex-public-key (util/hexify public-key)]
|
||||||
|
(spit @config/keys-filename {:private-key hex-private-key
|
||||||
|
:public-key hex-public-key})
|
||||||
|
(data-storage/read-keys)
|
||||||
|
(should= hex-public-key (mem/get-mem [:keys :public-key]))
|
||||||
|
(should= hex-private-key (mem/get-mem [:keys :private-key]))
|
||||||
|
(should= nil (mem/get-mem [:keys :password]))
|
||||||
|
(should= public-key (mem/get-mem :pubkey))))
|
||||||
|
|
||||||
|
(it "reads the keys with a password"
|
||||||
|
(let [bytes-private-key (util/make-private-key)
|
||||||
|
hex-private-key (util/hexify (util/bytes->num bytes-private-key))
|
||||||
|
bytes-public-key (es/get-pub-key bytes-private-key)
|
||||||
|
public-key (util/bytes->num bytes-public-key)
|
||||||
|
hex-public-key (util/hexify public-key)
|
||||||
|
password (bech32/encode-str "pw" "password")
|
||||||
|
encoded-private-key (->> hex-private-key
|
||||||
|
(util/xor-string "password")
|
||||||
|
(bech32/encode-str "encoded"))
|
||||||
|
]
|
||||||
|
|
||||||
|
(spit @config/keys-filename {:private-key encoded-private-key
|
||||||
|
:public-key hex-public-key
|
||||||
|
:password password})
|
||||||
|
(data-storage/read-keys)
|
||||||
|
(should= hex-public-key (mem/get-mem [:keys :public-key]))
|
||||||
|
(should= hex-private-key (mem/get-mem [:keys :private-key]))
|
||||||
|
(should= "password" (mem/get-mem [:keys :password]))
|
||||||
|
(should= public-key (mem/get-mem :pubkey))))
|
||||||
|
|
||||||
|
(it "writes the keys with no password"
|
||||||
|
(let [bytes-private-key (util/make-private-key)
|
||||||
|
hex-private-key (util/hexify (util/bytes->num bytes-private-key))
|
||||||
|
bytes-public-key (es/get-pub-key bytes-private-key)
|
||||||
|
public-key (util/bytes->num bytes-public-key)
|
||||||
|
hex-public-key (util/hexify public-key)]
|
||||||
|
(data-storage/write-keys {:private-key hex-private-key
|
||||||
|
:public-key hex-public-key})
|
||||||
|
(should= {:private-key hex-private-key
|
||||||
|
:public-key hex-public-key
|
||||||
|
:password nil}
|
||||||
|
(read-string (slurp @config/keys-filename)))))
|
||||||
|
|
||||||
|
(it "writes the keys with a password"
|
||||||
|
(let [bytes-private-key (util/make-private-key)
|
||||||
|
hex-private-key (util/hexify (util/bytes->num bytes-private-key))
|
||||||
|
bytes-public-key (es/get-pub-key bytes-private-key)
|
||||||
|
public-key (util/bytes->num bytes-public-key)
|
||||||
|
hex-public-key (util/hexify public-key)
|
||||||
|
encoded-private-key (->> hex-private-key
|
||||||
|
(util/xor-string "password")
|
||||||
|
(bech32/encode-str "encoded"))]
|
||||||
|
(data-storage/write-keys {:private-key hex-private-key
|
||||||
|
:public-key hex-public-key
|
||||||
|
:password "password"})
|
||||||
|
(should= {:private-key encoded-private-key
|
||||||
|
:public-key hex-public-key
|
||||||
|
:password (bech32/encode-str "pw" "password")}
|
||||||
|
(read-string (slurp @config/keys-filename)))))
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
@ -64,4 +64,19 @@
|
|||||||
pw gen-string]
|
pw gen-string]
|
||||||
(= source (->> source (xor-string pw) (xor-string pw)))
|
(= source (->> source (xor-string pw) (xor-string pw)))
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
(it "can write and read back xord strings"
|
||||||
|
(should-be
|
||||||
|
:result
|
||||||
|
(tc/quick-check
|
||||||
|
100
|
||||||
|
(prop/for-all
|
||||||
|
[source gen-string
|
||||||
|
pw gen-string]
|
||||||
|
(spit "xor-test.txt" (xor-string pw source))
|
||||||
|
(let [text (slurp "xor-test.txt")
|
||||||
|
decoded-source (xor-string pw text)]
|
||||||
|
(= source decoded-source)))))
|
||||||
|
(more-speech.util.files/delete-file "xor-test.txt")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
(with-redefs [event-composers/compose-and-send-metadata-event (stub :compose)
|
(with-redefs [event-composers/compose-and-send-metadata-event (stub :compose)
|
||||||
protocol/request-profiles-and-contacts-for (stub :request)
|
protocol/request-profiles-and-contacts-for (stub :request)
|
||||||
data-storage/write-keys (stub :write-keys)]
|
data-storage/write-keys (stub :write-keys)]
|
||||||
(let [private-key (rand-int 1000000000)
|
(let [private-key (util/bytes->num (util/make-private-key))
|
||||||
hex-private-key (util/hexify private-key)
|
hex-private-key (util/hexify private-key)
|
||||||
pubkey (->> private-key (util/num->bytes 32) es/get-pub-key util/bytes->num)
|
pubkey (->> private-key (util/num->bytes 32) es/get-pub-key util/bytes->num)
|
||||||
hex-pubkey (util/hexify pubkey)]
|
hex-pubkey (util/hexify pubkey)]
|
||||||
@ -48,7 +48,7 @@
|
|||||||
(with-redefs [event-composers/compose-and-send-metadata-event (stub :compose)
|
(with-redefs [event-composers/compose-and-send-metadata-event (stub :compose)
|
||||||
protocol/request-profiles-and-contacts-for (stub :request)
|
protocol/request-profiles-and-contacts-for (stub :request)
|
||||||
data-storage/write-keys (stub :write-keys)]
|
data-storage/write-keys (stub :write-keys)]
|
||||||
(let [private-key (rand-int 1000000000)
|
(let [private-key (util/bytes->num (util/make-private-key))
|
||||||
hex-private-key (util/hexify private-key)
|
hex-private-key (util/hexify private-key)
|
||||||
nsec-private-key (bech32/encode "nsec" private-key)
|
nsec-private-key (bech32/encode "nsec" private-key)
|
||||||
pubkey (->> private-key (util/num->bytes 32) es/get-pub-key util/bytes->num)
|
pubkey (->> private-key (util/num->bytes 32) es/get-pub-key util/bytes->num)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
(ns more-speech.data-storage
|
(ns more-speech.data-storage
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
|
[more-speech.bech32 :as bech32]
|
||||||
[more-speech.config :as config :refer [get-db]]
|
[more-speech.config :as config :refer [get-db]]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.db.gateway :as gateway]
|
||||||
[more-speech.db.in-memory :as in-memory]
|
[more-speech.db.in-memory :as in-memory]
|
||||||
@ -24,16 +25,28 @@
|
|||||||
(clojure.pprint/pprint (relays/relays-for-writing))))))
|
(clojure.pprint/pprint (relays/relays-for-writing))))))
|
||||||
|
|
||||||
(defn write-keys [keys]
|
(defn write-keys [keys]
|
||||||
(let [keys-string (with-out-str (clojure.pprint/pprint keys))]
|
(let [private-key (:private-key keys)
|
||||||
|
password (:password keys)
|
||||||
|
encoded-password (if (empty? password)
|
||||||
|
password
|
||||||
|
(bech32/encode-str "pw" password))
|
||||||
|
private-key (if (empty? password)
|
||||||
|
private-key
|
||||||
|
(->> private-key
|
||||||
|
(util/xor-string password)
|
||||||
|
(bech32/encode-str "encoded")))
|
||||||
|
keys (assoc keys :private-key private-key
|
||||||
|
:password encoded-password)
|
||||||
|
keys-string (with-out-str (clojure.pprint/pprint keys))]
|
||||||
(if (config/is-test-run?)
|
(if (config/is-test-run?)
|
||||||
(log-pr 2 `write-keys (dissoc keys :private-key))
|
(log-pr 2 `write-keys (dissoc keys :private-key))
|
||||||
(spit @config/keys-filename keys-string))))
|
(spit @config/keys-filename keys-string))))
|
||||||
|
|
||||||
(defn write-tabs []
|
(defn write-tabs []
|
||||||
(log-pr 2 'writing-tabs)
|
(log-pr 2 'writing-tabs)
|
||||||
(spit @config/tabs-list-filename
|
(spit @config/tabs-list-filename
|
||||||
(with-out-str
|
(with-out-str
|
||||||
(clojure.pprint/pprint (get-mem :tabs-list)))))
|
(clojure.pprint/pprint (get-mem :tabs-list)))))
|
||||||
|
|
||||||
(defn write-configuration []
|
(defn write-configuration []
|
||||||
(log-pr 2 'writing-relays)
|
(log-pr 2 'writing-relays)
|
||||||
@ -59,21 +72,34 @@
|
|||||||
(read-string (slurp @config/contact-lists-filename))
|
(read-string (slurp @config/contact-lists-filename))
|
||||||
{}))
|
{}))
|
||||||
|
|
||||||
(defn load-configuration []
|
(defn read-keys []
|
||||||
(let [keys (read-string (slurp @config/keys-filename))
|
(let [keys (read-string (slurp @config/keys-filename))
|
||||||
pubkey (util/hex-string->num (:public-key keys))
|
pubkey (util/hex-string->num (:public-key keys))
|
||||||
tabs-list (tabs/ensure-tab-list-has-all
|
pw (:password keys)
|
||||||
|
pw (if (empty? pw) nil
|
||||||
|
(bech32/address->str pw))
|
||||||
|
private-key (:private-key keys)
|
||||||
|
private-key (if (some? pw)
|
||||||
|
(util/xor-string pw (bech32/address->str private-key))
|
||||||
|
private-key)
|
||||||
|
]
|
||||||
|
(set-mem :keys (assoc keys :private-key private-key
|
||||||
|
:password pw))
|
||||||
|
(set-mem :pubkey pubkey)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn load-configuration []
|
||||||
|
(let [tabs-list (tabs/ensure-tab-list-has-all
|
||||||
(read-string (slurp @config/tabs-list-filename)))
|
(read-string (slurp @config/tabs-list-filename)))
|
||||||
user-configuration (user-configuration/validate
|
user-configuration (user-configuration/validate
|
||||||
(read-string (slurp @config/user-configuration-filename)))
|
(read-string (slurp @config/user-configuration-filename)))
|
||||||
profiles (read-profiles)
|
profiles (read-profiles)
|
||||||
contact-lists (read-contact-lists)
|
contact-lists (read-contact-lists)]
|
||||||
]
|
(read-keys)
|
||||||
(when (= :in-memory @config/db-type)
|
(when (= :in-memory @config/db-type)
|
||||||
(swap! in-memory/db assoc :contact-lists contact-lists)
|
(swap! in-memory/db assoc :contact-lists contact-lists)
|
||||||
(swap! in-memory/db assoc :profiles profiles))
|
(swap! in-memory/db assoc :profiles profiles))
|
||||||
(set-mem :keys keys)
|
|
||||||
(set-mem :pubkey pubkey)
|
|
||||||
(set-mem :tabs-list tabs-list)
|
(set-mem :tabs-list tabs-list)
|
||||||
(set-mem :user-configuration user-configuration)
|
(set-mem :user-configuration user-configuration)
|
||||||
(set-mem :event-history [])
|
(set-mem :event-history [])
|
||||||
@ -258,9 +284,9 @@
|
|||||||
(log-pr 1 'ingested n 'contact-lists))
|
(log-pr 1 'ingested n 'contact-lists))
|
||||||
(recur (rest contacts-in) (conj contacts-out (first contact-list)) (inc n)))))))
|
(recur (rest contacts-in) (conj contacts-out (first contact-list)) (inc n)))))))
|
||||||
|
|
||||||
(defn put-events [db events]
|
(defn put-events [db events]
|
||||||
(log-pr 1 'putting (count events) 'events)
|
(log-pr 1 'putting (count events) 'events)
|
||||||
(xt/submit-tx db (map #(vector ::xt/put %) events)))
|
(xt/submit-tx db (map #(vector ::xt/put %) events)))
|
||||||
|
|
||||||
(defn put-profiles [db profiles]
|
(defn put-profiles [db profiles]
|
||||||
(log-pr 1 'putting (count profiles) 'profiles)
|
(log-pr 1 'putting (count profiles) 'profiles)
|
||||||
@ -275,19 +301,19 @@
|
|||||||
(log-pr 1 'putting (count contacts) 'contacts)
|
(log-pr 1 'putting (count contacts) 'contacts)
|
||||||
(xt/submit-tx db (map #(vector ::xt/put (fix-contact-list %)) contacts)))
|
(xt/submit-tx db (map #(vector ::xt/put (fix-contact-list %)) contacts)))
|
||||||
|
|
||||||
(defn compress []
|
(defn compress []
|
||||||
(log-pr 1 'Compressing)
|
(log-pr 1 'Compressing)
|
||||||
(let [now (util/get-now)
|
(let [now (util/get-now)
|
||||||
event-since (- now (* 14 86400))
|
event-since (- now (* 14 86400))
|
||||||
profiles-since (- now (* 90 86400))
|
profiles-since (- now (* 90 86400))
|
||||||
contacts-since (- now (* 90 86400))
|
contacts-since (- now (* 90 86400))
|
||||||
prod-db (xtdb/start-xtdb! config/prod-db)
|
prod-db (xtdb/start-xtdb! config/prod-db)
|
||||||
temp-db (xtdb/start-xtdb! config/temp-db)]
|
temp-db (xtdb/start-xtdb! config/temp-db)]
|
||||||
(put-events temp-db (get-events-since prod-db event-since))
|
(put-events temp-db (get-events-since prod-db event-since))
|
||||||
(put-profiles temp-db (get-profiles-since prod-db profiles-since))
|
(put-profiles temp-db (get-profiles-since prod-db profiles-since))
|
||||||
(put-contacts temp-db (get-contacts-since prod-db contacts-since))
|
(put-contacts temp-db (get-contacts-since prod-db contacts-since))
|
||||||
(xt/sync temp-db)
|
(xt/sync temp-db)
|
||||||
(log-pr 1 'renaming config/prod-db (str config/prod-db "-old"))
|
(log-pr 1 'renaming config/prod-db (str config/prod-db "-old"))
|
||||||
(rename-file config/prod-db (str config/prod-db "-old"))
|
(rename-file config/prod-db (str config/prod-db "-old"))
|
||||||
(rename-file config/temp-db config/prod-db)))
|
(rename-file config/temp-db config/prod-db)))
|
||||||
|
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
(ns more-speech.migrator
|
(ns more-speech.migrator
|
||||||
(:require [more-speech.logger.default :refer [log-pr]]
|
(:require
|
||||||
[clojure.java.io :as io]
|
[more-speech.bech32 :as bech32]
|
||||||
[clojure.set :as set]
|
[more-speech.logger.default :refer [log-pr]]
|
||||||
[more-speech.config :refer [migration-filename]]
|
[clojure.java.io :as io]
|
||||||
[more-speech.config :as config]
|
[clojure.set :as set]
|
||||||
[more-speech.nostr
|
[more-speech.config :refer [migration-filename]]
|
||||||
[util :as util]
|
[more-speech.config :as config]
|
||||||
[elliptic-signature :as ecc]
|
[more-speech.nostr
|
||||||
[event-dispatcher :as handlers]]
|
[util :as util]
|
||||||
[more-speech.data-storage :as data-storage]
|
[elliptic-signature :as ecc]
|
||||||
[more-speech.user-configuration :as user-configuration]
|
[event-dispatcher :as handlers]]
|
||||||
[more-speech.db.gateway :as gateway]
|
[more-speech.data-storage :as data-storage]
|
||||||
[more-speech.util.files :refer :all]
|
[more-speech.user-configuration :as user-configuration]
|
||||||
[more-speech.initial-contact-list :as initial-contact-list]))
|
[more-speech.db.gateway :as gateway]
|
||||||
|
[more-speech.util.files :refer :all]
|
||||||
|
[more-speech.initial-contact-list :as initial-contact-list]))
|
||||||
|
|
||||||
;---The Migrations
|
;---The Migrations
|
||||||
|
|
||||||
@ -162,7 +164,19 @@
|
|||||||
(migration-10-load-contacts)
|
(migration-10-load-contacts)
|
||||||
(migration-10-load-events))
|
(migration-10-load-events))
|
||||||
|
|
||||||
|
;--- Migration 11 password protect private key
|
||||||
|
|
||||||
|
(defn migration-11-password-for-private-key []
|
||||||
|
(let [keys (read-string (slurp @config/keys-filename))
|
||||||
|
private-key (:private-key keys)
|
||||||
|
encoded-private-key (->> private-key
|
||||||
|
(util/xor-string "password")
|
||||||
|
(bech32/encode-str "encoded"))
|
||||||
|
encoded-keys (assoc keys :private-key encoded-private-key
|
||||||
|
:password (bech32/encode-str "pw" "password"))]
|
||||||
|
(spit @config/keys-filename (with-out-str (clojure.pprint/pprint encoded-keys)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
;---------- The Migrations List -------
|
;---------- The Migrations List -------
|
||||||
|
@ -177,13 +177,20 @@
|
|||||||
:size [800 :by 20])]
|
:size [800 :by 20])]
|
||||||
(left-right-split the-label the-field)))
|
(left-right-split the-label the-field)))
|
||||||
|
|
||||||
|
(defn- valid-password? []
|
||||||
|
(if (empty? (get-mem [:keys :password]))
|
||||||
|
true
|
||||||
|
(= (get-mem [:keys :password]) (input "Enter password"))))
|
||||||
|
|
||||||
(defn show-private-key [profile-frame _e]
|
(defn show-private-key [profile-frame _e]
|
||||||
(let [private-key-field (select profile-frame [:#private-key-field])
|
(let [private-key-field (select profile-frame [:#private-key-field])
|
||||||
show-box (select profile-frame [:#show-box])
|
show-box (select profile-frame [:#show-box])
|
||||||
show? (config show-box :selected?)]
|
show? (config show-box :selected?)
|
||||||
(config! private-key-field :text (if show?
|
allowed? (and show? (valid-password?))]
|
||||||
(get-mem [:keys :private-key])
|
(if allowed?
|
||||||
""))))
|
(config! private-key-field :text (get-mem [:keys :private-key]))
|
||||||
|
(do (config! private-key-field :text "")
|
||||||
|
(config! show-box :selected? false)))))
|
||||||
|
|
||||||
(defn make-private-key-panel [profile-frame]
|
(defn make-private-key-panel [profile-frame]
|
||||||
(let [the-label (label :text "Private key:" :size [150 :by 20])
|
(let [the-label (label :text "Private key:" :size [150 :by 20])
|
||||||
|
Loading…
Reference in New Issue
Block a user