[#5180] Encrypt account's db with password

This commit is contained in:
Roman Volosovskyi 2018-09-05 09:39:24 +03:00
parent 0dd008f7b9
commit c61200f9ae
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
11 changed files with 1348 additions and 3282 deletions

View File

@ -48,6 +48,7 @@ def prep(type = 'nightly') {
sh 'cp .env.jenkins .env'; break
}
common.installJSDeps('mobile')
sh 'cp patches/js_realm.hpp node_modules/realm/src/js_realm.hpp'
/* install ruby dependencies */
sh 'bundle install --quiet'
/* install Maven dependencies */

View File

@ -36,7 +36,9 @@
"react-native/Libraries/vendor/emitter/EventEmitter"
"react-native-background-timer"
"react-native-fetch-polyfill"
"react-native-testfairy"]
"react-native-testfairy"
"text-encoding"
"js-sha3"]
;; Resoures
:resource-dirs ["resources/images"]

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@
"homoglyph-finder": "1.1.1",
"identicon.js": "github:status-im/identicon.js",
"instabug-reactnative": "2.12.0",
"js-sha3": "^0.8.0",
"level-filesystem": "1.2.0",
"metro": "^0.30.2",
"nfc-react-native": "github:status-im/nfc-react-native",
@ -80,6 +81,7 @@
"realm": "git+https://github.com/status-im/realm-js.git",
"rn-snoopy": "github:status-im/rn-snoopy",
"string_decoder": "0.10.31",
"text-encoding": "^0.6.4",
"url": "0.10.3",
"web3": "github:status-im/web3.js#feature/shhext"
},

View File

@ -4683,6 +4683,11 @@
"merge-stream": "1.0.1"
}
},
"js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
@ -7988,6 +7993,11 @@
}
}
},
"text-encoding": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
"integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk="
},
"then-request": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz",

View File

@ -24,6 +24,7 @@
"homoglyph-finder": "1.1.1",
"identicon.js": "https://github.com/status-im/identicon.js.git",
"instabug-reactnative": "2.12.0",
"js-sha3": "^0.8.0",
"level-filesystem": "1.2.0",
"process": "0.11.10",
"prop-types": "15.6.0",
@ -60,6 +61,7 @@
"realm": "2.15.3",
"rn-snoopy": "https://github.com/status-im/rn-snoopy.git",
"string_decoder": "0.10.31",
"text-encoding": "^0.6.4",
"url": "0.10.3",
"web3": "https://github.com/status-im/web3.js.git#feature/shhext"
}

1193
patches/js_realm.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,12 +24,11 @@
(defn clear-web-data! []
(status/clear-web-data))
(defn change-account! [address]
(defn change-account! [address password]
;; No matter what is the keychain we use, as checks are done on decrypting base
(.. (keychain/safe-get-encryption-key)
(then (fn [encryption-key]
(data-store/change-account address encryption-key)
(re-frame/dispatch [:init.callback/account-change-success address])))
(then #(data-store/change-account address password %))
(then (fn [] (re-frame/dispatch [:init.callback/account-change-success address])))
(catch (fn [error]
(log/warn "Could not change account" error)
;; If all else fails we fallback to showing initial error
@ -52,7 +51,7 @@
(if success
(let [{:keys [address password save-password?]} (accounts.db/credentials cofx)]
(merge {:accounts.login/clear-web-data nil
:data-store/change-account address}
:data-store/change-account [address password]}
(when save-password?
{:keychain/save-user-password [address password]})))
{:db (update db :accounts/login assoc
@ -92,5 +91,5 @@
(re-frame/reg-fx
:data-store/change-account
(fn [address]
(change-account! address)))
(fn [[address password]]
(change-account! address password)))

View File

@ -24,9 +24,9 @@
(log/error "Could not move realms" error)))
(then #(data-source/open-base-realm encryption-key)))))
(defn change-account [address encryption-key]
(defn change-account [address password encryption-key]
(log/debug "changing account to: " address)
(data-source/change-account address encryption-key))
(data-source/change-account address password encryption-key))
(defn- perform-transactions [raw-transactions realm]
(let [success-events (keep :success-event raw-transactions)

View File

@ -11,28 +11,33 @@
[status-im.utils.ethereum.core :as utils.ethereum]
[cognitect.transit :as transit]
[status-im.react-native.js-dependencies :as rn-dependencies]
[status-im.utils.utils :as utils]))
[status-im.js-dependencies :as js-dependencies]))
(defn to-buffer [key]
(when key
(let [length (.-length key)
arr (js/Uint8Array. length)]
(dotimes [i length]
(aset arr i (aget key i)))
(.-buffer arr))))
(when-not (nil? key)
(when key
(let [length (.-length key)
arr (js/Int8Array. length)]
(dotimes [i length]
(aset arr i (aget key i)))
arr))))
(defn encrypted-realm-version
"Returns -1 if the file does not exists, the schema version if it successfully
decrypts it, error otherwise."
decrypts it, throws error otherwise."
[file-name encryption-key]
(.schemaVersion rn-dependencies/realm file-name (to-buffer encryption-key)))
(log/info "encrypted-realm-version\nfile: " file-name " buf " (str encryption-key) (nil? encryption-key))
(if encryption-key
(.schemaVersion rn-dependencies/realm file-name (to-buffer encryption-key))
(.schemaVersion rn-dependencies/realm file-name)))
(defn open-realm
[options file-name encryption-key]
(log/debug "Opening realm at " file-name "...")
(let [options-js (clj->js (assoc options :path file-name))]
(log/debug "Using encryption key...")
(set! (.-encryptionKey options-js) (to-buffer encryption-key))
(when encryption-key
(set! (.-encryptionKey options-js) (to-buffer encryption-key)))
(when (exists? js/window)
(rn-dependencies/realm. options-js))))
@ -55,10 +60,10 @@
utils.platform/android? (str
(.-DocumentDirectoryPath rn-dependencies/fs)
"/../no_backup/realm/")
utils.platform/ios? (str
(.-LibraryDirectoryPath rn-dependencies/fs)
"/realm/")
:else (.-defaultPath rn-dependencies/realm)))
utils.platform/ios? (str
(.-LibraryDirectoryPath rn-dependencies/fs)
"/realm/")
:else (.-defaultPath rn-dependencies/realm)))
(def old-realm-dir
(string/replace old-base-realm-path #"default\.realm$" ""))
@ -105,15 +110,34 @@
(defn- migrate-schemas
"Apply migrations in sequence and open database with the last schema"
[file-name schemas encryption-key current-version]
(log/info "migrate schemas")
(doseq [schema schemas
:when (> (:schemaVersion schema) current-version)
:let [migrated-realm (open-realm schema file-name encryption-key)]]
(close migrated-realm))
(open-realm (last schemas) file-name encryption-key))
(defn keccak512-array [key]
(.array (.-keccak512 js-dependencies/js-sha3) key))
(defn merge-Uint8Arrays [arr1 arr2]
(let [arr1-length (.-length arr1)
arr2-length (.-length arr2)
arr (js/Uint8Array. (+ arr1-length arr2-length))]
(.set arr arr1)
(.set arr arr2 arr1-length)
arr))
(defn db-encryption-key [password encryption-key]
(let [password-array (.encode
(new (.-TextEncoder js-dependencies/text-encoding))
password)]
(keccak512-array (merge-Uint8Arrays encryption-key password-array))))
(defn migrate-realm
"Migrate realm if is a compatible version or reset the database"
[file-name schemas encryption-key]
(log/info "migrate-realm")
(migrate-schemas file-name schemas encryption-key (encrypted-realm-version
file-name
encryption-key)))
@ -125,8 +149,8 @@
(defn- index-entity-schemas [all-schemas]
(into {} (map (juxt :name identity)) (-> all-schemas last :schema)))
(def base-realm (atom nil))
(def account-realm (atom nil))
(defonce base-realm (atom nil))
(defonce account-realm (atom nil))
(def entity->schemas (merge (index-entity-schemas base/schemas)
(index-entity-schemas account/schemas)))
@ -144,10 +168,66 @@
(reset! base-realm (open-migrated-realm base-realm-path base/schemas encryption-key))
(log/debug "Created @base-realm"))
(defn change-account [address encryption-key]
(let [path (str accounts-realm-dir (utils.ethereum/sha3 address))]
(defn re-encrypt-realm
[file-name old-key new-key on-success on-error]
(let [old-file-name (str file-name "old")]
(.. (fs/move-file file-name old-file-name)
(then #(fs/unlink (str file-name ".lock")))
(then #(fs/unlink (str file-name ".management")))
(then #(fs/unlink (str file-name ".note")))
(catch (fn [e]
(let [message (str "can't move old database " (str e) " " file-name)]
(log/debug message)
(on-error {:error message}))))
(then (fn []
(let [old-account-db (open-migrated-realm old-file-name
account/schemas
old-key)]
(log/info "copy old database")
(log/info "with key: " (str new-key))
(.writeCopyTo old-account-db file-name (to-buffer new-key))
(log/info "old database copied")
(close old-account-db)
(log/info "old database closed")
(on-success)
(fs/unlink old-file-name)
(log/info "old database removed"))))
(catch (fn [e]
(try (fs/move-file old-file-name file-name)
(catch :default _))
(let [message (str "something went wrong " (str e) " " file-name)]
(log/info message)
(on-error {:error message})))))))
(defn check-db-encryption
[file-name old-key new-key]
(js/Promise.
(fn [on-success on-error]
(try
(do
(log/info "try to encrypt with password")
(encrypted-realm-version file-name new-key)
(log/info "try to encrypt with password success")
(on-success))
(catch :default _
(do
(log/info "try to encrypt with old key")
(encrypted-realm-version file-name old-key)
(log/info "try to encrypt with old key success")
(re-encrypt-realm file-name old-key new-key on-success on-error)))))))
(defn change-account [address password encryption-key]
(let [path (str accounts-realm-dir (utils.ethereum/sha3 address))
account-db-key (db-encryption-key password encryption-key)]
(close-account-realm)
(reset! account-realm (open-migrated-realm path account/schemas encryption-key))))
(..
(check-db-encryption path encryption-key account-db-key)
(then
(fn []
(log/info "change-account done" (nil? @account-realm))
(reset! account-realm
(open-migrated-realm path account/schemas account-db-key))
(log/info "account-realm " (nil? @account-realm)))))))
(declare realm-obj->clj)
@ -235,10 +315,10 @@
(defmulti to-query (fn [_ operator _ _] operator))
(defmethod to-query :eq [schema-name _ field value]
(let [field-type (field-type schema-name field)
query (str (name field) "=" (if (= "string" (name field-type))
(str "\"" value "\"")
value))]
(let [field-type (field-type schema-name field)
query (str (name field) "=" (if (= "string" (name field-type))
(str "\"" value "\"")
value))]
query))
(defn get-by-field

View File

@ -5,3 +5,5 @@
(def homoglyph-finder (js/require "homoglyph-finder"))
(def identicon-js (js/require "identicon.js"))
(def Web3 (js/require "web3"))
(def text-encoding (js/require "text-encoding"))
(def js-sha3 (js/require "js-sha3"))