[#4772] Resolve ENS domains in browser
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
parent
b7b6a252e1
commit
c96bc5aa8b
3
deps.edn
3
deps.edn
|
@ -11,7 +11,8 @@
|
|||
com.taoensso/timbre {:mvn/version "4.10.0"}
|
||||
hickory {:mvn/version "0.7.1"}
|
||||
com.cognitect/transit-cljs {:mvn/version "0.8.248"}
|
||||
status-im/pluto {:mvn/version "iteration-2-SNAPSHOT"}}
|
||||
status-im/pluto {:mvn/version "iteration-2-SNAPSHOT"}
|
||||
mvxcvi/alphabase {:mvn/version "1.0.0"}}
|
||||
|
||||
:aliases
|
||||
{:dev {:extra-deps
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
[com.taoensso/timbre "4.10.0"]
|
||||
[hickory "0.7.1"]
|
||||
[com.cognitect/transit-cljs "0.8.248"]
|
||||
[status-im/pluto "iteration-2-SNAPSHOT"]]
|
||||
[status-im/pluto "iteration-2-SNAPSHOT"]
|
||||
[mvxcvi/alphabase "1.0.0"]]
|
||||
:plugins [[lein-cljsbuild "1.1.7"]
|
||||
[lein-re-frisk "0.5.8"]
|
||||
[lein-cljfmt "0.5.7"]
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
[status-im.data-store.dapp-permissions :as dapp-permissions]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.screens.browser.default-dapps :as default-dapps]
|
||||
[status-im.utils.http :as http]))
|
||||
[status-im.utils.http :as http]
|
||||
[clojure.string :as string]
|
||||
[status-im.utils.ethereum.resolver :as resolver]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.utils.ethereum.ens :as ens]
|
||||
[status-im.utils.multihash :as multihash]
|
||||
[status-im.utils.handlers-macro :as handlers-macro]))
|
||||
|
||||
(defn get-current-url [{:keys [history history-index]}]
|
||||
(when (and history-index history)
|
||||
|
@ -24,13 +30,13 @@
|
|||
(assoc browser :dapp? true :name (:name dapp))
|
||||
(assoc browser :dapp? false :name (i18n/label :t/browser)))))
|
||||
|
||||
(defn update-browser-fx [{:keys [db now]} browser]
|
||||
(defn update-browser-fx [browser {:keys [db now]}]
|
||||
(let [updated-browser (check-if-dapp-in-list (assoc browser :timestamp now))]
|
||||
{:db (update-in db [:browser/browsers (:browser-id updated-browser)]
|
||||
merge updated-browser)
|
||||
:data-store/tx [(browser-store/save-browser-tx updated-browser)]}))
|
||||
|
||||
(defn update-browser-history-fx [cofx browser url loading?]
|
||||
(defn update-browser-history-fx [browser url loading? cofx]
|
||||
(when-not loading?
|
||||
(let [history-index (:history-index browser)
|
||||
history (:history browser)
|
||||
|
@ -43,12 +49,41 @@
|
|||
new-index (if slash?
|
||||
history-index
|
||||
(dec (count new-history)))]
|
||||
(update-browser-fx cofx
|
||||
(assoc browser :history new-history :history-index new-index)))))))
|
||||
(update-browser-fx (assoc browser :history new-history :history-index new-index)
|
||||
cofx))))))
|
||||
|
||||
(defn update-browser-and-navigate [cofx browser]
|
||||
(merge (update-browser-fx cofx browser)
|
||||
{:dispatch [:navigate-to :browser (:browser-id browser)]}))
|
||||
(defn ens? [host]
|
||||
(string/ends-with? host ".eth"))
|
||||
|
||||
(defn ens-multihash-callback [hex]
|
||||
(let [hash (when hex (multihash/base58 (multihash/create :sha2-256 (subs hex 2))))]
|
||||
(if (and hash (not= hash resolver/default-hash))
|
||||
(re-frame/dispatch [:ens-multihash-resolved hash])
|
||||
(re-frame/dispatch [:update-browser-options {:resolving? false}]))))
|
||||
|
||||
(defn resolve-multihash-fx [host loading error? {{:keys [web3 network] :as db} :db}]
|
||||
(let [network (get-in db [:account/account :networks network])
|
||||
chain (ethereum/network->chain-keyword network)]
|
||||
(if (and (not loading) (not error?) (ens? host))
|
||||
{:db (assoc-in db [:browser/options :resolving?] true)
|
||||
:resolve-ens-multihash {:web3 web3
|
||||
:registry (get ens/ens-registries
|
||||
chain)
|
||||
:ens-name host
|
||||
:cb ens-multihash-callback}}
|
||||
{})))
|
||||
|
||||
(defn update-new-browser-and-navigate [host browser cofx]
|
||||
(handlers-macro/merge-fx
|
||||
cofx
|
||||
{:dispatch [:navigate-to :browser {:browser-id (:browser-id browser)
|
||||
:resolving? (ens? host)}]}
|
||||
(update-browser-fx browser)
|
||||
(resolve-multihash-fx host false false)))
|
||||
|
||||
(defn update-browser-and-navigate [browser cofx]
|
||||
(merge (update-browser-fx browser cofx)
|
||||
{:dispatch [:navigate-to :browser {:browser-id (:browser-id browser)}]}))
|
||||
|
||||
(def permissions {constants/dapp-permission-contact-code {:title (i18n/label :t/wants-to-access-profile)
|
||||
:description (i18n/label :t/your-contact-code)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
(spec/def :browser/history (spec/nilable vector?))
|
||||
(spec/def :browser/history-index (spec/nilable int?))
|
||||
(spec/def :browser/loading? (spec/nilable boolean?))
|
||||
(spec/def :browser/resolving? (spec/nilable boolean?))
|
||||
(spec/def :browser/url-editing? (spec/nilable boolean?))
|
||||
(spec/def :browser/show-tooltip (spec/nilable keyword?))
|
||||
(spec/def :browser/show-permission (spec/nilable map?))
|
||||
|
@ -19,6 +20,7 @@
|
|||
(allowed-keys
|
||||
:opt-un [:browser/browser-id
|
||||
:browser/loading?
|
||||
:browser/resolving?
|
||||
:browser/url-editing?
|
||||
:browser/show-tooltip
|
||||
:browser/show-permission
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
[status-im.utils.random :as random]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.universal-links.core :as utils.universal-links]
|
||||
[taoensso.timbre :as log]))
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.ethereum.resolver :as resolver]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:browse
|
||||
|
@ -39,72 +40,89 @@
|
|||
(fn [[message webview]]
|
||||
(.sendToBridge webview (types/clj->json message))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:resolve-ens-multihash
|
||||
(fn [{:keys [web3 registry ens-name cb]}]
|
||||
(resolver/content web3 registry ens-name cb)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:browse-link-from-message
|
||||
(fn [_ [_ link]]
|
||||
{:browse link}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:ens-multihash-resolved
|
||||
(fn [{:keys [db] :as cofx} [_ hash]]
|
||||
(let [options (:browser/options db)
|
||||
browsers (:browser/browsers db)
|
||||
browser (get browsers (:browser-id options))
|
||||
history-index (:history-index browser)]
|
||||
(handlers-macro/merge-fx
|
||||
cofx
|
||||
{:db (assoc-in db [:browser/options :resolving?] false)}
|
||||
(model/update-browser-fx
|
||||
(assoc-in browser [:history history-index] (str "https://ipfs.infura.io/ipfs/" hash)))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:open-url-in-browser
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [url]]
|
||||
(let [normalized-url (http/normalize-and-decode-url url)]
|
||||
(model/update-browser-and-navigate cofx {:browser-id (or (http/url-host normalized-url) (random/id))
|
||||
:history-index 0
|
||||
:history [normalized-url]}))))
|
||||
(fn [cofx [_ url]]
|
||||
(let [normalized-url (http/normalize-and-decode-url url)
|
||||
host (http/url-host normalized-url)]
|
||||
(model/update-new-browser-and-navigate
|
||||
host
|
||||
{:browser-id (or host (random/id))
|
||||
:history-index 0
|
||||
:history [normalized-url]}
|
||||
cofx))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:send-to-bridge
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [message]]
|
||||
(fn [cofx [_ message]]
|
||||
{:send-to-bridge-fx [message (get-in cofx [:db :webview-bridge])]}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:open-browser
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [browser]]
|
||||
(model/update-browser-and-navigate cofx browser)))
|
||||
(fn [cofx [_ browser]]
|
||||
(model/update-browser-and-navigate browser cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:update-browser-on-nav-change
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [browser url loading]]
|
||||
(model/update-browser-history-fx cofx browser url loading)))
|
||||
(fn [cofx [_ browser url loading error?]]
|
||||
(let [host (http/url-host url)]
|
||||
(handlers-macro/merge-fx
|
||||
cofx
|
||||
(model/resolve-multihash-fx host loading error?)
|
||||
(model/update-browser-history-fx browser url loading)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:update-browser-options
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [options]]
|
||||
(fn [{:keys [db]} [_ options]]
|
||||
{:db (update db :browser/options merge options)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:remove-browser
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db]} [browser-id]]
|
||||
(fn [{:keys [db]} [_ browser-id]]
|
||||
{:db (update-in db [:browser/browsers] dissoc browser-id)
|
||||
:data-store/tx [(browser-store/remove-browser-tx browser-id)]}))
|
||||
|
||||
(defn nav-update-browser [cofx browser history-index]
|
||||
(model/update-browser-fx cofx (assoc browser :history-index history-index)))
|
||||
(model/update-browser-fx (assoc browser :history-index history-index) cofx))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:browser-nav-back
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [{:keys [history-index] :as browser}]]
|
||||
(fn [cofx [_ {:keys [history-index] :as browser}]]
|
||||
(when (pos? history-index)
|
||||
(nav-update-browser cofx browser (dec history-index)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:browser-nav-forward
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [{:keys [history-index] :as browser}]]
|
||||
(fn [cofx [_ {:keys [history-index] :as browser}]]
|
||||
(when (< history-index (dec (count (:history browser))))
|
||||
(nav-update-browser cofx browser (inc history-index)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:on-bridge-message
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db] :as cofx} [message]]
|
||||
(fn [{:keys [db] :as cofx} [_ message]]
|
||||
(let [{:browser/keys [options browsers]} db
|
||||
{:keys [browser-id]} options
|
||||
browser (get browsers browser-id)
|
||||
|
@ -113,7 +131,7 @@
|
|||
(cond
|
||||
|
||||
(and (= type constants/history-state-changed) platform/ios? (not= "about:blank" url))
|
||||
(model/update-browser-history-fx cofx browser url false)
|
||||
(model/update-browser-history-fx browser url false cofx)
|
||||
|
||||
(= type constants/web3-send-async)
|
||||
(model/web3-send-async payload messageId cofx)
|
||||
|
@ -127,7 +145,6 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:check-permissions-queue
|
||||
[re-frame/trim-v]
|
||||
(fn [{:keys [db] :as cofx} _]
|
||||
(let [{:keys [show-permission permissions-queue]} (:browser/options db)]
|
||||
(when (and (nil? show-permission) (last permissions-queue))
|
||||
|
@ -145,9 +162,8 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:next-dapp-permission
|
||||
[re-frame/trim-v]
|
||||
(fn [cofx [params permission permissions-data]]
|
||||
(fn [cofx [_ params permission permissions-data]]
|
||||
(model/next-permission {:params params
|
||||
:permission permission
|
||||
:permissions-data permissions-data}
|
||||
cofx)))
|
||||
cofx)))
|
|
@ -2,5 +2,5 @@
|
|||
(:require [status-im.ui.screens.navigation :as navigation]))
|
||||
|
||||
(defmethod navigation/preload-data! :browser
|
||||
[db [_ _ browser-id]]
|
||||
(assoc db :browser/options {:browser-id browser-id}))
|
||||
[db [_ _ options]]
|
||||
(assoc db :browser/options options))
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
(re-frame/dispatch [:update-browser-on-nav-change
|
||||
browser
|
||||
(http/normalize-and-decode-url @url-text)
|
||||
false
|
||||
false]))
|
||||
:placeholder (i18n/label :t/enter-url)
|
||||
:auto-capitalize :none
|
||||
|
@ -81,12 +82,12 @@
|
|||
[react/text {:style styles/web-view-error-text}
|
||||
(str desc)]]))
|
||||
|
||||
(defn on-navigation-change [event browser]
|
||||
(defn on-navigation-change [event browser error?]
|
||||
(let [{:strs [url loading]} (js->clj event)]
|
||||
(when platform/ios?
|
||||
(re-frame/dispatch [:update-browser-options {:loading? loading}]))
|
||||
(when (not= "about:blank" url)
|
||||
(re-frame/dispatch [:update-browser-on-nav-change browser url loading]))))
|
||||
(re-frame/dispatch [:update-browser-on-nav-change browser url loading error?]))))
|
||||
|
||||
(defn get-inject-js [url]
|
||||
(let [domain-name (nth (re-find #"^\w+://(www\.)?([^/:]+)" url) 2)]
|
||||
|
@ -115,7 +116,7 @@
|
|||
(views/letsubs [webview (atom nil)
|
||||
{:keys [address]} [:get-current-account]
|
||||
{:keys [browser-id dapp? name] :as browser} [:get-current-browser]
|
||||
{:keys [error? loading? url-editing? show-tooltip show-permission]} [:get :browser/options]
|
||||
{:keys [error? loading? url-editing? show-tooltip show-permission resolving?]} [:get :browser/options]
|
||||
rpc-url [:get :rpc-url]
|
||||
network-id [:get-network-id]]
|
||||
(let [can-go-back? (model/can-go-back? browser)
|
||||
|
@ -131,12 +132,12 @@
|
|||
:ref #(do
|
||||
(reset! webview %)
|
||||
(re-frame/dispatch [:set :webview-bridge %]))
|
||||
:source {:uri url}
|
||||
:source (when-not resolving? {:uri url})
|
||||
:java-script-enabled true
|
||||
:bounces false
|
||||
:local-storage-enabled true
|
||||
:render-error web-view-error
|
||||
:on-navigation-state-change #(on-navigation-change % browser)
|
||||
:on-navigation-state-change #(on-navigation-change % browser error?)
|
||||
:on-bridge-message #(re-frame/dispatch [:on-bridge-message %])
|
||||
:on-load #(re-frame/dispatch [:update-browser-options {:error? false}])
|
||||
:on-error #(re-frame/dispatch [:update-browser-options {:error? true
|
||||
|
@ -148,7 +149,7 @@
|
|||
(ethereum/normalized-address address)
|
||||
(str network-id)))
|
||||
:injected-java-script js-res/webview-js}]
|
||||
(when loading?
|
||||
(when (or loading? resolving?)
|
||||
[react/view styles/web-view-loading
|
||||
[components/activity-indicator {:animating true}]])]
|
||||
[navigation webview browser can-go-back? can-go-forward?]
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
(spec/def :navigation/prev-view-id (spec/nilable keyword?))
|
||||
;; navigation screen params
|
||||
(spec/def :navigation.screen-params/network-details (allowed-keys :req [:networks/selected-network]))
|
||||
(spec/def :navigation.screen-params/browser (spec/nilable string?))
|
||||
(spec/def :navigation.screen-params/browser (spec/nilable map?))
|
||||
(spec/def :navigation.screen-params.profile-qr-viewer/contact (spec/nilable map?))
|
||||
(spec/def :navigation.screen-params.profile-qr-viewer/source (spec/nilable keyword?))
|
||||
(spec/def :navigation.screen-params.profile-qr-viewer/value (spec/nilable string?))
|
||||
|
|
|
@ -70,6 +70,11 @@
|
|||
(namehash ens-name))
|
||||
(fn [_ address] (cb (ethereum/hex->address address)))))
|
||||
|
||||
(defn content [web3 resolver ens-name cb]
|
||||
(ethereum/call web3
|
||||
(ethereum/call-params resolver "content(bytes32)" (namehash ens-name))
|
||||
(fn [_ hash] (cb hash))))
|
||||
|
||||
(def ABI-hash "0x2203ab56")
|
||||
(def pubkey-hash "0xc8690233")
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
(ns status-im.utils.ethereum.resolver
|
||||
(:require [status-im.utils.ethereum.ens :as ens]))
|
||||
|
||||
(def default-address "0x0000000000000000000000000000000000000000")
|
||||
(def default-hash "0x0000000000000000000000000000000000000000000000000000000000000000")
|
||||
|
||||
(defn content [web3 registry ens-name cb]
|
||||
(ens/resolver web3
|
||||
registry
|
||||
ens-name
|
||||
(fn [address]
|
||||
(if (and address (not= address default-address))
|
||||
(ens/content web3 address ens-name cb)
|
||||
(cb nil)))))
|
|
@ -0,0 +1,185 @@
|
|||
(ns status-im.utils.multihash
|
||||
"Core multihash type definition and helper methods."
|
||||
(:require
|
||||
[alphabase.base58 :as b58]
|
||||
[alphabase.bytes :as bytes]
|
||||
[alphabase.hex :as hex]))
|
||||
|
||||
(def ^:const algorithm-codes
|
||||
"Map of information about the available content hashing algorithms."
|
||||
{:sha1 0x11
|
||||
:sha2-256 0x12
|
||||
:sha2-512 0x13
|
||||
:sha3 0x14
|
||||
:blake2b 0x40
|
||||
:blake2s 0x41})
|
||||
|
||||
(defn app-code?
|
||||
"True if the given code number is assigned to the application-specfic range.
|
||||
Returns nil if the argument is not an integer."
|
||||
[code]
|
||||
(when (integer? code)
|
||||
(< 0 code 0x10)))
|
||||
|
||||
(defn get-algorithm
|
||||
"Looks up an algorithm by keyword name or code number. Returns `nil` if the
|
||||
value does not map to any valid algorithm."
|
||||
[value]
|
||||
(cond
|
||||
(keyword? value)
|
||||
(when-let [code (get algorithm-codes value)]
|
||||
{:code code, :name value})
|
||||
|
||||
(not (integer? value))
|
||||
nil
|
||||
|
||||
(app-code? value)
|
||||
{:code value, :name (keyword (str "app-" value))}
|
||||
|
||||
:else
|
||||
(some #(when (= value (val %))
|
||||
{:code value, :name (key %)})
|
||||
algorithm-codes)))
|
||||
|
||||
;; ## Multihash Type
|
||||
|
||||
;; Multihash identifiers have two properties:
|
||||
;;
|
||||
;; - `code` is a numeric code for an algorithm entry in `algorithm-codes` or an
|
||||
;; application-specific algorithm code.
|
||||
;; - `hex-digest` is a string holding the hex-encoded algorithm output.
|
||||
;;
|
||||
;; Multihash values also support metadata.
|
||||
(deftype Multihash [code hex-digest _meta]
|
||||
|
||||
Object
|
||||
|
||||
(toString
|
||||
[this]
|
||||
(str "hash:" (name (:name (get-algorithm code))) \: hex-digest))
|
||||
|
||||
(-equiv
|
||||
[this that]
|
||||
(cond
|
||||
(identical? this that) true
|
||||
(instance? Multihash that)
|
||||
(and (= code (:code that))
|
||||
(= hex-digest (:hex-digest that)))
|
||||
:else false))
|
||||
|
||||
IHash
|
||||
|
||||
(-hash
|
||||
[this]
|
||||
(hash-combine code hex-digest))
|
||||
|
||||
IComparable
|
||||
|
||||
(-compare
|
||||
[this that]
|
||||
(cond
|
||||
(= this that) 0
|
||||
(< code (:code that)) -1
|
||||
(> code (:code that)) 1
|
||||
:else (compare hex-digest (:hex-digest that))))
|
||||
|
||||
ILookup
|
||||
|
||||
(-lookup
|
||||
[this k]
|
||||
(-lookup this k nil))
|
||||
|
||||
(-lookup
|
||||
[this k not-found]
|
||||
(case k
|
||||
:code code
|
||||
:algorithm (:name (get-algorithm code))
|
||||
:length (/ (count hex-digest) 2)
|
||||
:digest (hex/decode hex-digest)
|
||||
:hex-digest hex-digest
|
||||
not-found))
|
||||
|
||||
IMeta
|
||||
|
||||
(-meta
|
||||
[this]
|
||||
_meta)
|
||||
|
||||
IWithMeta
|
||||
|
||||
(-with-meta
|
||||
[this meta-map]
|
||||
(Multihash. code hex-digest meta-map)))
|
||||
|
||||
(defn create
|
||||
"Constructs a new Multihash identifier. Accepts either a numeric algorithm
|
||||
code or a keyword name as the first argument. The digest may either by a byte
|
||||
array or a hex string."
|
||||
[algorithm digest]
|
||||
(let [algo (get-algorithm algorithm)]
|
||||
(when-not (integer? (:code algo))
|
||||
(throw (ex-info
|
||||
(str "Argument " (pr-str algorithm) " does not "
|
||||
"represent a valid hash algorithm.")
|
||||
{:algorithm algorithm})))
|
||||
(let [hex-digest (if (string? digest) digest (hex/encode digest))
|
||||
byte-len (/ (count hex-digest) 2)]
|
||||
(when (< 127 byte-len)
|
||||
(throw (ex-info (str "Digest length must be less than 128 bytes: "
|
||||
byte-len)
|
||||
{:length byte-len})))
|
||||
(when-let [err (hex/validate hex-digest)]
|
||||
(throw (ex-info err {:hex-digest hex-digest})))
|
||||
(->Multihash (:code algo) hex-digest nil))))
|
||||
|
||||
;; ## Encoding and Decoding
|
||||
|
||||
(defn encode
|
||||
"Encodes a multihash into a binary representation."
|
||||
^bytes
|
||||
[mhash]
|
||||
(let [length (:length mhash)
|
||||
encoded (bytes/byte-array (+ length 2))]
|
||||
(bytes/set-byte encoded 0 (:code mhash))
|
||||
(bytes/set-byte encoded 1 length)
|
||||
(bytes/copy (:digest mhash) 0 encoded 2 length)
|
||||
encoded))
|
||||
|
||||
(defn hex
|
||||
"Encodes a multihash into a hexadecimal string."
|
||||
[mhash]
|
||||
(when mhash
|
||||
(hex/encode (encode mhash))))
|
||||
|
||||
(defn base58
|
||||
"Encodes a multihash into a Base-58 string."
|
||||
[mhash]
|
||||
(when mhash
|
||||
(b58/encode (encode mhash))))
|
||||
|
||||
(defn decode-array
|
||||
"Decodes a byte array directly into multihash. Throws `ex-info` with a `:type`
|
||||
of `:multihash/bad-input` if the data is malformed or invalid."
|
||||
[^bytes encoded]
|
||||
(let [encoded-size (alength encoded)
|
||||
min-size 3]
|
||||
(when (< encoded-size min-size)
|
||||
(throw (ex-info
|
||||
(str "Cannot read multihash from byte array: " encoded-size
|
||||
" is less than the minimum of " min-size)
|
||||
{:type :multihash/bad-input}))))
|
||||
(let [code (bytes/get-byte encoded 0)
|
||||
length (bytes/get-byte encoded 1)
|
||||
payload (- (alength encoded) 2)]
|
||||
(when-not (pos? length)
|
||||
(throw (ex-info
|
||||
(str "Encoded length " length " is invalid")
|
||||
{:type :multihash/bad-input})))
|
||||
(when (< payload length)
|
||||
(throw (ex-info
|
||||
(str "Encoded digest length " length " exceeds actual "
|
||||
"remaining payload of " payload " bytes")
|
||||
{:type :multihash/bad-input})))
|
||||
(let [digest (bytes/byte-array length)]
|
||||
(bytes/copy encoded 2 digest 0 length)
|
||||
(create code digest))))
|
Loading…
Reference in New Issue