[#5583]: Stronger security checks in browser; Metamask phishing detector
Signed-off-by: Aleksandr Pantiukhov <alwxndr@gmail.com>
This commit is contained in:
parent
5d912caf4a
commit
eda73bf8ef
|
@ -26,6 +26,7 @@
|
|||
"instabug-reactnative"
|
||||
"react-native-http-bridge"
|
||||
"emojilib"
|
||||
"eth-phishing-detect"
|
||||
"react-native-config"
|
||||
"react-native-svg"
|
||||
"react-native-keychain"
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
"chance",
|
||||
"react-native-http-bridge",
|
||||
"emojilib",
|
||||
"eth-phishing-detect",
|
||||
"react-native-config",
|
||||
"react-native-svg",
|
||||
"react-native-keychain",
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
"create-react-class": "15.6.2",
|
||||
"dns.js": "1.0.1",
|
||||
"emojilib": "2.2.9",
|
||||
"eth-phishing-detect": "1.1.13",
|
||||
"events": "1.1.1",
|
||||
"google-breakpad": "git+https://github.com/status-im/google-breakpad.git",
|
||||
"homoglyph-finder": "1.1.1",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"create-react-class": "15.6.2",
|
||||
"dns.js": "1.0.1",
|
||||
"emojilib": "2.2.9",
|
||||
"eth-phishing-detect": "1.1.13",
|
||||
"events": "1.1.1",
|
||||
"homoglyph-finder": "1.1.1",
|
||||
"identicon.js": "https://github.com/status-im/identicon.js.git",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 13.9513C11 14.5035 10.5522 14.9513 10 14.9513C9.44775 14.9513 9 14.5035 9 13.9513V9.0304C9 9.0304 9 8 10 8C10.8345 8 11 8.88428 11 9.0304V13.9513Z" fill="#000000" fill-rule="evenodd"/>
|
||||
<path d="M11 6C11 6.55225 10.5522 7 10 7C9.44775 7 9 6.55225 9 6C9 5.44775 9.44775 5 10 5C10.5522 5 11 5.44775 11 6Z" fill="#000000" fill-rule="evenodd"/>
|
||||
<path d="M0 10C0 15.5228 4.47705 20 10 20C15.5229 20 20 15.5228 20 10C20 4.47717 15.5229 0 10 0C4.47705 0 0 4.47717 0 10ZM18 10C18 14.4183 14.4182 18 10 18C5.58179 18 2 14.4183 2 10C2 5.58167 5.58179 2 10 2C14.4182 2 18 5.58167 18 10Z" fill="#000000" fill-rule="evenodd"/>
|
||||
</svg>
|
After Width: | Height: | Size: 729 B |
|
@ -2,6 +2,7 @@
|
|||
|
||||
(def Chance (js/require "chance"))
|
||||
(def emojis (js/require "emojilib"))
|
||||
(def phishing-detect (js/require "eth-phishing-detect"))
|
||||
(def homoglyph-finder (js/require "homoglyph-finder"))
|
||||
(def identicon-js (js/require "identicon.js"))
|
||||
(def Web3 (js/require "web3"))
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
(ns status-im.models.browser
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.data-store.browser :as browser-store]
|
||||
[status-im.data-store.dapp-permissions :as dapp-permissions]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[status-im.ui.screens.browser.default-dapps :as default-dapps]
|
||||
[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]
|
||||
|
@ -31,8 +32,14 @@
|
|||
(assoc browser :dapp? true :name (:name dapp))
|
||||
(assoc browser :dapp? false :name (i18n/label :t/browser)))))
|
||||
|
||||
(defn check-if-phishing-url [{:keys [history history-index] :as browser}]
|
||||
(let [history-host (http/url-host (try (nth history history-index) (catch js/Error _)))]
|
||||
(assoc browser :unsafe? (dependencies/phishing-detect history-host))))
|
||||
|
||||
(defn update-browser-fx [browser {:keys [db now]}]
|
||||
(let [updated-browser (check-if-dapp-in-list (assoc browser :timestamp now))]
|
||||
(let [updated-browser (-> (assoc browser :timestamp now)
|
||||
(check-if-dapp-in-list)
|
||||
(check-if-phishing-url))]
|
||||
{:db (update-in db [:browser/browsers (:browser-id updated-browser)]
|
||||
merge updated-browser)
|
||||
:data-store/tx [(browser-store/save-browser-tx updated-browser)]}))
|
||||
|
|
|
@ -91,7 +91,8 @@
|
|||
:icons/camera (js/require "./resources/icons/camera.svg")
|
||||
:icons/check (js/require "./resources/icons/check.svg")
|
||||
:icons/dots (js/require "./resources/icons/dots.svg")
|
||||
:icons/warning (js/require "./resources/icons/warning.svg")}
|
||||
:icons/warning (js/require "./resources/icons/warning.svg")
|
||||
:icons/info (js/require "./resources/icons/info.svg")}
|
||||
{:icons/discover (components.svg/slurp-svg "./resources/icons/bottom/discover_gray.svg")
|
||||
:icons/contacts (components.svg/slurp-svg "./resources/icons/bottom/contacts_gray.svg")
|
||||
:icons/home (components.svg/slurp-svg "./resources/icons/bottom/home_gray.svg")
|
||||
|
@ -156,6 +157,7 @@
|
|||
:icons/check (components.svg/slurp-svg "./resources/icons/check.svg")
|
||||
:icons/dots (components.svg/slurp-svg "./resources/icons/dots.svg")
|
||||
:icons/warning (components.svg/slurp-svg "./resources/icons/warning.svg")
|
||||
:icons/info (components.svg/slurp-svg "./resources/icons/info.svg")
|
||||
:icons/settings (components.svg/slurp-svg "./resources/icons/settings.svg")}))
|
||||
|
||||
(defn normalize-property-name [n]
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
:opt-un [:browser/name
|
||||
:browser/dapp?
|
||||
:browser/history
|
||||
:browser/history-index]))
|
||||
:browser/history-index
|
||||
:browser/unsafe?]))
|
||||
|
||||
(spec/def :browser/browsers (spec/nilable (spec/map-of :global/not-empty-string :browser/browser)))
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
(ns status-im.ui.screens.browser.site-blocked.styles
|
||||
(:require-macros [status-im.utils.styles :refer [defstyle defnstyle]])
|
||||
(:require [status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:justify-content :center
|
||||
:flex 1
|
||||
:background-color colors/gray-lighter})
|
||||
|
||||
(def container-root-view
|
||||
{:flex 1
|
||||
:margin 24
|
||||
:justify-content :center
|
||||
:align-items :center})
|
||||
|
||||
(defstyle title-text
|
||||
{:color colors/black
|
||||
:font-size 17
|
||||
:font-weight :bold
|
||||
:margin-top 26
|
||||
:margin-bottom 10
|
||||
:line-height 20
|
||||
:text-align :center
|
||||
:ios {:letter-spacing -0.4}})
|
||||
|
||||
(defstyle description-text
|
||||
{:color colors/gray
|
||||
:font-size 15
|
||||
:line-height 22
|
||||
:text-align :center
|
||||
:ios {:letter-spacing -0.2}})
|
||||
|
||||
(def chat-link-text
|
||||
{:color colors/blue})
|
||||
|
||||
(def buttons-container
|
||||
{:flex-direction :row
|
||||
:justify-content :center
|
||||
:margin-top 24})
|
|
@ -0,0 +1,36 @@
|
|||
(ns status-im.ui.screens.browser.site-blocked.views
|
||||
(:require-macros [status-im.utils.views :as views])
|
||||
(:require [reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.button.view :as button]
|
||||
[status-im.ui.screens.browser.site-blocked.styles :as styles]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.icons.vector-icons :as vector-icons]))
|
||||
|
||||
(defn chat-link []
|
||||
[react/text {:on-press #(.openURL react/linking "status-im://chat/public/status")
|
||||
:style styles/chat-link-text}
|
||||
"#status"])
|
||||
|
||||
(views/defview view [{:keys [can-go-back?]}]
|
||||
[react/scroll-view {:keyboard-should-persist-taps :always
|
||||
:bounces false
|
||||
:content-container-style styles/container}
|
||||
[react/view styles/container-root-view
|
||||
[vector-icons/icon :icons/info {:color colors/red}]
|
||||
[react/text {:style styles/title-text}
|
||||
(i18n/label :t/browsing-site-blocked-title)]
|
||||
[react/text {:style styles/description-text}
|
||||
(i18n/label :t/browsing-site-blocked-description1)
|
||||
[chat-link]
|
||||
[react/text (i18n/label :t/browsing-site-blocked-description2)]]
|
||||
[react/view styles/buttons-container
|
||||
[components.common/button {:on-press (fn []
|
||||
(let [handler (if can-go-back?
|
||||
:browser-nav-back
|
||||
:navigate-back)]
|
||||
(re-frame/dispatch [handler])))
|
||||
:label (i18n/label :t/browsing-site-blocked-go-back)}]]]])
|
|
@ -1,27 +1,28 @@
|
|||
(ns status-im.ui.screens.browser.views
|
||||
(:require-macros [status-im.utils.slurp :refer [slurp]]
|
||||
[status-im.utils.views :as views])
|
||||
(:require [cljs.reader :as reader]
|
||||
(:require [clojure.string :as string]
|
||||
[cljs.reader :as reader]
|
||||
[reagent.core :as reagent]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.browser.styles :as styles]
|
||||
[status-im.ui.components.react :as components]
|
||||
[status-im.ui.components.status-bar.view :as status-bar]
|
||||
[status-im.ui.components.toolbar.view :as toolbar.view]
|
||||
[status-im.ui.components.webview-bridge :as components.webview-bridge]
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
[status-im.ui.components.react :as components]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.ui.components.toolbar.actions :as actions]
|
||||
[status-im.ui.components.tooltip.views :as tooltip]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.screens.browser.permissions.views :as permissions.views]
|
||||
[status-im.ui.screens.browser.site-blocked.views :as site-blocked.views]
|
||||
[status-im.ui.screens.browser.styles :as styles]
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
[status-im.utils.ethereum.core :as ethereum]
|
||||
[status-im.models.browser :as model]
|
||||
[status-im.utils.http :as http]
|
||||
[status-im.ui.components.styles :as components.styles]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[clojure.string :as string]
|
||||
[status-im.ui.screens.browser.permissions.views :as permissions.views]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def browser-config
|
||||
|
@ -116,9 +117,9 @@
|
|||
;; should-component-update is called only when component's props are changed,
|
||||
;; that's why it can't be used in `brwoser`, because `url` comes from subs
|
||||
(views/defview browser-component
|
||||
[{:keys [webview error? url browser browser-id can-go-back? can-go-forward?
|
||||
url-editing? resolving? network-id address show-permission
|
||||
show-tooltip opt-in? loading? dapp? rpc-url name]}]
|
||||
[{:keys [webview error? url browser browser-id unsafe? can-go-back?
|
||||
can-go-forward? url-editing? resolving? network-id address
|
||||
show-permission show-tooltip opt-in? loading? dapp? rpc-url name]}]
|
||||
{:should-component-update (fn [_ _ args]
|
||||
(let [[_ props] args]
|
||||
(not (nil? (:url props)))))}
|
||||
|
@ -126,31 +127,34 @@
|
|||
[status-bar/status-bar]
|
||||
[toolbar webview error? url browser browser-id url-editing?]
|
||||
[react/view components.styles/flex
|
||||
[components.webview-bridge/webview-bridge
|
||||
{:dapp? dapp?
|
||||
:dapp-name name
|
||||
:ref #(do
|
||||
(reset! webview %)
|
||||
(re-frame/dispatch [:set :webview-bridge %]))
|
||||
: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 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
|
||||
:loading? false}])
|
||||
:injected-on-start-loading-java-script (str (not opt-in?) js-res/web3
|
||||
(get-inject-js url)
|
||||
(if opt-in?
|
||||
(js-res/web3-opt-in-init (str network-id))
|
||||
(js-res/web3-init
|
||||
rpc-url
|
||||
(ethereum/normalized-address address)
|
||||
(str network-id))))
|
||||
:injected-java-script js-res/webview-js}]
|
||||
(if unsafe?
|
||||
[site-blocked.views/view {:can-go-back? can-go-back?
|
||||
:site browser-id}]
|
||||
[components.webview-bridge/webview-bridge
|
||||
{:dapp? dapp?
|
||||
:dapp-name name
|
||||
:ref #(do
|
||||
(reset! webview %)
|
||||
(re-frame/dispatch [:set :webview-bridge %]))
|
||||
: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 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
|
||||
:loading? false}])
|
||||
:injected-on-start-loading-java-script (str (not opt-in?) js-res/web3
|
||||
(get-inject-js url)
|
||||
(if opt-in?
|
||||
(js-res/web3-opt-in-init (str network-id))
|
||||
(js-res/web3-init
|
||||
rpc-url
|
||||
(ethereum/normalized-address address)
|
||||
(str network-id))))
|
||||
:injected-java-script js-res/webview-js}])
|
||||
(when (or loading? resolving?)
|
||||
[react/view styles/web-view-loading
|
||||
[components/activity-indicator {:animating true}]])]
|
||||
|
@ -166,7 +170,7 @@
|
|||
(views/defview browser []
|
||||
(views/letsubs [webview (atom nil)
|
||||
{:keys [address settings]} [:get-current-account]
|
||||
{:keys [browser-id dapp? name] :as browser} [:get-current-browser]
|
||||
{:keys [browser-id dapp? name unsafe?] :as browser} [:get-current-browser]
|
||||
{:keys [error? loading? url-editing? show-tooltip show-permission resolving?]} [:get :browser/options]
|
||||
rpc-url [:get :rpc-url]
|
||||
network-id [:get-network-id]]
|
||||
|
@ -180,6 +184,7 @@
|
|||
:url url
|
||||
:browser browser
|
||||
:browser-id browser-id
|
||||
:unsafe? unsafe?
|
||||
:can-go-back? can-go-back?
|
||||
:can-go-forward? can-go-forward?
|
||||
:url-editing? url-editing?
|
||||
|
|
|
@ -183,6 +183,10 @@
|
|||
"use-valid-qr-code": "This QR code doesn't contain a valid universal link, contact code or username: {{data}}",
|
||||
"paste-json": "Paste JSON",
|
||||
"browsing-title": "Browse",
|
||||
"browsing-site-blocked-title": "This site is blocked",
|
||||
"browsing-site-blocked-description1": "We detected potential malicious activity from this address. To protect you and your wallet, we're preventing further navigation.\n\nIf you think this is an error, let us know in the ",
|
||||
"browsing-site-blocked-description2": " public chat.",
|
||||
"browsing-site-blocked-go-back": "Go back",
|
||||
"wallet-add-asset": "Add asset",
|
||||
"mainnet-is-default-alert-title": "Hello",
|
||||
"delete-message": "Delete message",
|
||||
|
|
Loading…
Reference in New Issue