From 42abd16e9ab8a2a95b8f0042ba0cf11601f24a9d Mon Sep 17 00:00:00 2001 From: Andrey Shovkoplyas Date: Tue, 14 Aug 2018 15:04:22 +0300 Subject: [PATCH] [#5260] Implement web3 provider Opt-in access Signed-off-by: Andrey Shovkoplyas --- resources/icons/settings.svg | 3 + resources/js/web3_init.js | 11 ++- resources/js/webview.js | 7 ++ src/status_im/constants.cljs | 1 + src/status_im/models/browser.cljs | 33 ++++--- src/status_im/translations/en.cljs | 9 +- .../ui/components/chat_icon/screen.cljs | 12 +++ .../ui/components/icons/vector_icons.cljs | 3 +- src/status_im/ui/screens/browser/db.cljs | 4 + src/status_im/ui/screens/browser/events.cljs | 60 +++++++------ .../ui/screens/browser/permissions/views.cljs | 83 +++++++++++++++++ src/status_im/ui/screens/browser/styles.cljs | 89 +++++++++++++++++++ src/status_im/ui/screens/browser/views.cljs | 72 ++++++++------- test/cljs/status_im/test/browser/events.cljs | 20 +++++ 14 files changed, 330 insertions(+), 77 deletions(-) create mode 100644 resources/icons/settings.svg create mode 100644 src/status_im/ui/screens/browser/permissions/views.cljs diff --git a/resources/icons/settings.svg b/resources/icons/settings.svg new file mode 100644 index 0000000000..9d3ca2205c --- /dev/null +++ b/resources/icons/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/js/web3_init.js b/resources/js/web3_init.js index ccd411dabd..e4dc221121 100644 --- a/resources/js/web3_init.js +++ b/resources/js/web3_init.js @@ -10,8 +10,15 @@ WebViewBridge.onMessage = function (message) { else if (data.type === "status-api-success") { - window.STATUS_API = data.data; - window.postMessage({ type: 'STATUS_API_SUCCESS', permissions: data.keys }, "*"); + if (data.keys == 'WEB3') + { + window.dispatchEvent(new CustomEvent('ethereumprovider', { detail: { ethereum: new StatusHttpProvider("")} })); + } + else + { + window.STATUS_API = data.data; + window.postMessage({ type: 'STATUS_API_SUCCESS', permissions: data.keys }, "*"); + } } else if (data.type === "web3-send-async-callback") diff --git a/resources/js/webview.js b/resources/js/webview.js index 679cc2ca08..a3f19d6471 100644 --- a/resources/js/webview.js +++ b/resources/js/webview.js @@ -24,5 +24,12 @@ host: window.location.hostname }); } + else if (event.data.type === 'ETHEREUM_PROVIDER_REQUEST') { + bridgeSend({ + type: 'status-api-request', + permissions: ['WEB3'], + host: window.location.hostname + }); + } }); }()); diff --git a/src/status_im/constants.cljs b/src/status_im/constants.cljs index 9093d58053..bb4a54cb7e 100644 --- a/src/status_im/constants.cljs +++ b/src/status_im/constants.cljs @@ -246,6 +246,7 @@ (def regx-emoji #"^((?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F|[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])+$") (def ^:const dapp-permission-contact-code "CONTACT_CODE") +(def ^:const dapp-permission-web3 "WEB3") (def ^:const status-api-success "status-api-success") (def ^:const status-api-request "status-api-request") (def ^:const history-state-changed "history-state-changed") diff --git a/src/status_im/models/browser.cljs b/src/status_im/models/browser.cljs index f857727528..d5f2eb94c6 100644 --- a/src/status_im/models/browser.cljs +++ b/src/status_im/models/browser.cljs @@ -50,16 +50,23 @@ (merge (update-browser-fx cofx browser) {:dispatch [:navigate-to :browser (:browser-id browser)]})) -(def permissions {constants/dapp-permission-contact-code {:label (i18n/label :t/your-contact-code)}}) +(def permissions {constants/dapp-permission-contact-code {:title (i18n/label :t/wants-to-access-profile) + :description (i18n/label :t/your-contact-code) + :icon :icons/profile-active} + constants/dapp-permission-web3 {:title (i18n/label :t/dapp-would-like-to-connect-wallet) + :description (i18n/label :t/allowing-authorizes-this-dapp) + :icon :icons/wallet-active}}) (defn update-dapp-permissions-fx [{:keys [db]} permissions] - {:db (assoc-in db [:dapps/permissions (:dapp permissions)] permissions) + {:db (-> db + (assoc-in [:browser/options :show-permission] nil) + (assoc-in [:dapps/permissions (:dapp permissions)] permissions)) :data-store/tx [(dapp-permissions/save-dapp-permissions permissions)]}) -(defn request-permission [cofx - {:keys [dapp-name index requested-permissions permissions-allowed user-permissions - permissions-data webview] - :as params}] +(defn request-permission [{:keys [dapp-name index requested-permissions permissions-allowed user-permissions + permissions-data] + :as params} + {:keys [db] :as cofx}] ;; iterate all requested permissions (if (< index (count requested-permissions)) (let [requested-permission (get requested-permissions index)] @@ -68,7 +75,8 @@ ;; if permission already allowed go to next, if not, show confirmation dialog (if ((set user-permissions) requested-permission) {:dispatch [:next-dapp-permission params requested-permission permissions-data]} - {:show-dapp-permission-confirmation-fx [requested-permission params]}) + {:db (assoc-in db [:browser/options :show-permission] {:requested-permission requested-permission + :params params})}) {:dispatch [:next-dapp-permission params]})) (assoc (update-dapp-permissions-fx cofx {:dapp dapp-name :permissions (vec (set (concat (keys permissions-allowed) @@ -76,19 +84,20 @@ :send-to-bridge-fx [{:type constants/status-api-success :data permissions-allowed :keys (keys permissions-allowed)} - webview]))) + (:webview-bridge db)] + :dispatch [:check-permissions-queue]))) -(defn next-permission [cofx params & [permission permissions-data]] +(defn next-permission [{:keys [params permission permissions-data]} cofx] (request-permission - cofx (cond-> params true (update :index inc) (and permission permissions-data) - (assoc-in [:permissions-allowed permission] (get permissions-data permission))))) + (assoc-in [:permissions-allowed permission] (get permissions-data permission))) + cofx)) -(defn web3-send-async [{:keys [db]} {:keys [method] :as payload} message-id] +(defn web3-send-async [{:keys [method] :as payload} message-id {:keys [db]}] (if (or (= method constants/web3-send-transaction) (= method constants/web3-personal-sign)) {:db (update-in db [:wallet :transactions-queue] conj {:message-id message-id :payload payload}) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 6a5e584451..a7c4fe9d1d 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -720,5 +720,10 @@ :browser-secure "Connection is secure. Make sure you really trust this site before signing transactions or entering personal data." :browser-not-secure "Connection is not secure! Do not sign transactions or send personal data on this site." :make-sure-you-trust-dapp "Make sure that you trust this DApp" - :would-like-to-access "Would like to Access" - :your-contact-code "Your Contact Code"}) + :wants-to-access-profile "wants to access to your profile" + :your-contact-code "Granting access authorizes this DApp to retrieve your contact code" + :dapp-would-like-to-connect-wallet "would like\n to connect to your wallet" + :allowing-authorizes-this-dapp "Allowing authorizes this DApp to retrieve your wallet address and enable Web3" + :manage-permissions "Manage permissions" + :deny "Deny" + :allow "Allow"}) diff --git a/src/status_im/ui/components/chat_icon/screen.cljs b/src/status_im/ui/components/chat_icon/screen.cljs index 99c7c433d0..e7ff2a27dd 100644 --- a/src/status_im/ui/components/chat_icon/screen.cljs +++ b/src/status_im/ui/components/chat_icon/screen.cljs @@ -149,6 +149,18 @@ :default-chat-icon (styles/default-chat-icon-chat-list components.styles/default-chat-color) :default-chat-icon-text styles/default-chat-icon-text}]) +(defn dapp-icon-permission [contact size] + [contact-icon-view contact + {:container {:width size :height size} + :online-view-wrapper styles/online-view-wrapper + :online-view styles/online-view + :online-dot-left styles/online-dot-left + :online-dot-right styles/online-dot-right + :size size + :chat-icon (styles/custom-size-icon size) + :default-chat-icon (styles/default-chat-icon-profile components.styles/default-chat-color size) + :default-chat-icon-text styles/default-chat-icon-text}]) + (defn profile-icon-view [photo-path name color edit? size] (let [styles {:container {:width size :height size} :online-view styles/online-view-profile diff --git a/src/status_im/ui/components/icons/vector_icons.cljs b/src/status_im/ui/components/icons/vector_icons.cljs index 53ad9d3e5b..22d691913c 100644 --- a/src/status_im/ui/components/icons/vector_icons.cljs +++ b/src/status_im/ui/components/icons/vector_icons.cljs @@ -151,7 +151,8 @@ :icons/camera (components.svg/slurp-svg "./resources/icons/camera.svg") :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/warning (components.svg/slurp-svg "./resources/icons/warning.svg") + :icons/settings (components.svg/slurp-svg "./resources/icons/settings.svg")})) (defn normalize-property-name [n] (if (= n :icons/options) diff --git a/src/status_im/ui/screens/browser/db.cljs b/src/status_im/ui/screens/browser/db.cljs index d425b5eceb..64010a44dc 100644 --- a/src/status_im/ui/screens/browser/db.cljs +++ b/src/status_im/ui/screens/browser/db.cljs @@ -12,6 +12,8 @@ (spec/def :browser/loading? (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?)) +(spec/def :browser/permissions-queue (spec/nilable any?)) (spec/def :browser/options (allowed-keys @@ -19,6 +21,8 @@ :browser/loading? :browser/url-editing? :browser/show-tooltip + :browser/show-permission + :browser/permissions-queue :browser/error?])) (spec/def :browser/browser diff --git a/src/status_im/ui/screens/browser/events.cljs b/src/status_im/ui/screens/browser/events.cljs index 636fe471bf..e258ed3f07 100644 --- a/src/status_im/ui/screens/browser/events.cljs +++ b/src/status_im/ui/screens/browser/events.cljs @@ -3,18 +3,19 @@ [status-im.utils.handlers :as handlers] [re-frame.core :as re-frame] [status-im.utils.random :as random] - [status-im.i18n :as i18n] [status-im.ui.components.list-selection :as list-selection] [status-im.utils.universal-links.core :as utils.universal-links] [status-im.data-store.browser :as browser-store] [status-im.utils.http :as http] [status-im.models.browser :as model] [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils] [status-im.constants :as constants] [status-im.native-module.core :as status] [taoensso.timbre :as log] - [status-im.utils.types :as types])) + [status-im.utils.handlers-macro :as handlers-macro] + [status-im.utils.types :as types] + [status-im.utils.handlers-macro :as handlers-macro] + [status-im.constants :as constants])) (re-frame/reg-fx :browse @@ -40,18 +41,6 @@ (fn [[message webview]] (.sendToBridge webview (types/clj->json message)))) -(re-frame/reg-fx - :show-dapp-permission-confirmation-fx - (fn [[permission {:keys [dapp-name permissions-data] :as params}]] - (utils/show-confirmation - {:ios-confirm-style "default"} - (str "\"" dapp-name "\" " (i18n/label :t/would-like-to-access) " " (:label (get model/permissions permission))) - (i18n/label :t/make-sure-you-trust-dapp) - nil - #(re-frame/dispatch [:next-dapp-permission params permission permissions-data]) - #(re-frame/dispatch [:next-dapp-permission params]) - (i18n/label :t/dont-allow)))) - (handlers/register-handler-fx :initialize-browsers [(re-frame/inject-cofx :data-store/all-browsers)] @@ -132,10 +121,10 @@ :on-bridge-message [re-frame/trim-v] (fn [{:keys [db] :as cofx} [message]] - (let [{:browser/keys [options browsers] :keys [webview-bridge]} db + (let [{:browser/keys [options browsers]} db {:keys [browser-id]} options browser (get browsers browser-id) - data (types/json->clj message) + data (types/json->clj message) {{:keys [url]} :navState :keys [type host permissions payload messageId]} data] (cond @@ -143,23 +132,38 @@ (model/update-browser-history-fx cofx browser url false) (= type constants/web3-send-async) - (model/web3-send-async cofx payload messageId) + (model/web3-send-async payload messageId cofx) (= type constants/status-api-request) - (let [{:account/keys [account]} db - {:keys [dapp? name]} browser + (let [{:keys [dapp? name]} browser dapp-name (if dapp? name host)] - (model/request-permission + {:db (update-in db [:browser/options :permissions-queue] conj {:dapp-name dapp-name + :permissions permissions}) + :dispatch [:check-permissions-queue]}))))) + +(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)) + (let [{:keys [dapp-name permissions]} (last permissions-queue) + {:account/keys [account]} db] + (handlers-macro/merge-fx cofx - {:dapp-name dapp-name - :webview webview-bridge - :index 0 - :user-permissions (get-in db [:dapps/permissions dapp-name :permissions]) - :requested-permissions permissions - :permissions-data {constants/dapp-permission-contact-code (:public-key account)}})))))) + {:db (update-in db [:browser/options :permissions-queue] drop-last)} + (model/request-permission + {:dapp-name dapp-name + :index 0 + :user-permissions (get-in db [:dapps/permissions dapp-name :permissions]) + :requested-permissions permissions + :permissions-data {constants/dapp-permission-contact-code (:public-key account)}}))))))) (handlers/register-handler-fx :next-dapp-permission [re-frame/trim-v] (fn [cofx [params permission permissions-data]] - (model/next-permission cofx params permission permissions-data))) \ No newline at end of file + (model/next-permission {:params params + :permission permission + :permissions-data permissions-data} + cofx))) \ No newline at end of file diff --git a/src/status_im/ui/screens/browser/permissions/views.cljs b/src/status_im/ui/screens/browser/permissions/views.cljs new file mode 100644 index 0000000000..b1c3d3d69f --- /dev/null +++ b/src/status_im/ui/screens/browser/permissions/views.cljs @@ -0,0 +1,83 @@ +(ns status-im.ui.screens.browser.permissions.views + (:require-macros [status-im.utils.views :as views]) + (:require [status-im.ui.components.animation :as anim] + [status-im.ui.components.react :as react] + [status-im.ui.screens.browser.styles :as styles] + [re-frame.core :as re-frame] + [status-im.i18n :as i18n] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.icons.vector-icons :as icons] + [status-im.ui.components.colors :as colors] + [reagent.core :as reagent] + [status-im.models.browser :as model] + [status-im.ui.components.chat-icon.screen :as chat-icon.screen])) + +(views/defview permissions-panel [{:keys [dapp? name] :as browser} {:keys [requested-permission params]}] + (views/letsubs [dapp [:get-dapp-by-name name] + bottom-anim-value (anim/create-value -354) + alpha-value (anim/create-value 0) + hide-panel #(anim/start + (anim/parallel + [(anim/spring bottom-anim-value {:toValue -354}) + (anim/timing alpha-value {:toValue 0 + :duration 500})]))] + {:component-did-mount #(anim/start + (anim/parallel + [(anim/spring bottom-anim-value {:toValue -20}) + (anim/timing alpha-value {:toValue 0.6 + :duration 500})]))} + (let [_ (when-not requested-permission (js/setTimeout hide-panel 10)) + {:keys [dapp-name]} params + {:keys [title description icon]} (get model/permissions requested-permission)] + [react/view styles/permissions-panel-container + [react/animated-view {:style (styles/permissions-panel-background alpha-value)}] + [react/animated-view {:style (styles/permissions-panel bottom-anim-value)} + [react/view styles/permissions-panel-icons-container + (if dapp? + [chat-icon.screen/dapp-icon-permission dapp 48] + [react/view styles/permissions-panel-dapp-icon-container + [react/text {:style styles/permissions-panel-d-label} "Ð"]]) + [react/view {:margin-left 3 :margin-right 3} + [react/view styles/dot]] + [react/view {:margin-right 3} + [react/view styles/dot]] + [react/view styles/permissions-panel-ok-icon-container + [icons/icon :icons/ok styles/permissions-panel-ok-ico]] + [react/view {:margin-left 3 :margin-right 3} + [react/view styles/dot]] + [react/view {:margin-right 3} + [react/view styles/dot]] + [react/view styles/permissions-panel-wallet-icon-container + (when icon + [icons/icon icon {:color :white}])]] + [react/text {:style styles/permissions-panel-title-label} + (str "\"" dapp-name "\" " title)] + [react/text {:style styles/permissions-panel-description-label} + description] + [react/view {:flex-direction :row :margin-top 14} + [components.common/button {:on-press #(re-frame/dispatch [:next-dapp-permission params]) + :label (i18n/label :t/deny)}] + [react/view {:width 16}] + [components.common/button {:on-press #(re-frame/dispatch [:next-dapp-permission params requested-permission + (:permissions-data params)]) + :label (i18n/label :t/allow)}]] + ;; TODO (andrey) will be in next PR + #_[react/view {:flex-direction :row :margin-top 19} + [icons/icon :icons/settings {:color colors/blue}] + [react/text {:style styles/permissions-panel-permissions-label} + (i18n/label :t/manage-permissions)]]]]))) + +;; NOTE (andrey) we need this complex function, to show animation before component will be unmounted +(defn permissions-anim-panel [browser show-permission] + (let [timeout (atom nil) + render? (reagent/atom false)] + (fn [browser show-permission] + (if show-permission + (do + (when @timeout + (js/clearTimeout @timeout) + (reset! timeout nil)) + (when-not @render? (reset! render? true))) + (reset! timeout (js/setTimeout #(reset! render? false) 600))) + (when @render? + [permissions-panel browser show-permission])))) diff --git a/src/status_im/ui/screens/browser/styles.cljs b/src/status_im/ui/screens/browser/styles.cljs index f1de41f12e..4768cfaa58 100644 --- a/src/status_im/ui/screens/browser/styles.cljs +++ b/src/status_im/ui/screens/browser/styles.cljs @@ -82,3 +82,92 @@ :letter-spacing -0.2 :margin-horizontal 5}) +(def dot + {:height 4 + :width 4 + :background-color "#E4E6EB" + :border-radius 2}) + +(def permissions-panel-container + {:position :absolute + :top 0 + :bottom 0 + :right 0 + :left 0}) + +(defn permissions-panel-background [alpha-value] + {:flex 1 + :background-color colors/black + :opacity alpha-value}) + +(defn permissions-panel [bottom-anim-value] + {:height 354 + :position :absolute + :bottom bottom-anim-value + :right 0 + :left 0 + :align-items :center + :background-color :white + :border-top-left-radius 8 + :border-top-right-radius 8}) + +(def permissions-panel-icons-container + {:margin-top 26 + :align-items :center + :justify-content :center + :flex-direction :row}) + +(def permissions-panel-dapp-icon-container + {:height 48 + :width 48 + :background-color "#E4E6EB" + :border-radius 24 + :align-items :center + :justify-content :center}) + +(def permissions-panel-d-label + {:font-size 22 + :color colors/gray + :font-weight :bold}) + +(def permissions-panel-ok-icon-container + {:height 24 + :width 24 + :background-color "#48EA77" + :border-radius 12 + :align-items :center + :justify-content :center}) + +(def permissions-panel-ok-ico + {:color :white + :width 12 + :height 12}) + +(def permissions-panel-wallet-icon-container + {:height 48 + :width 48 + :background-color colors/blue + :border-radius 24 + :align-items :center + :justify-content :center}) + +(def permissions-panel-title-label + {:margin-horizontal 20 + :font-size 22 + :line-height 28 + :text-align :center + :margin-top 19 + :font-weight :bold}) + +(def permissions-panel-description-label + {:margin-horizontal 20 + :color colors/gray + :font-size 15 + :line-height 22 + :text-align :center + :margin-top 9}) + +(def permissions-panel-permissions-label + {:color colors/blue + :font-size 14 + :margin-left 10}) \ No newline at end of file diff --git a/src/status_im/ui/screens/browser/views.cljs b/src/status_im/ui/screens/browser/views.cljs index c83515f9f7..bc7eecb5d7 100644 --- a/src/status_im/ui/screens/browser/views.cljs +++ b/src/status_im/ui/screens/browser/views.cljs @@ -20,7 +20,8 @@ [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])) + [clojure.string :as string] + [status-im.ui.screens.browser.permissions.views :as permissions.views])) (def browser-config (reader/read-string (slurp "./src/status_im/utils/browser_config.edn"))) @@ -55,6 +56,21 @@ [react/touchable-highlight {:style {:flex 1} :on-press #(re-frame/dispatch [:update-browser-options {:url-editing? true}])} [react/text {:style styles/url-text} (http/url-host url)]])]])) +(defn toolbar [webview error? url browser browser-id url-editing?] + [toolbar.view/toolbar {} + [toolbar.view/nav-button-with-count + (actions/close (fn [] + (when @webview + (.sendToBridge @webview "navigate-to-blank")) + (re-frame/dispatch [:navigate-back]) + (when error? + (re-frame/dispatch [:remove-browser browser-id]))))] + [toolbar-content url browser error? url-editing?] + [toolbar.view/actions [{:icon :icons/wallet + :icon-opts {:color :black + :accessibility-label :wallet-modal-button} + :handler #(re-frame/dispatch [:navigate-to-modal :wallet-modal])}]]]) + (defn- web-view-error [_ code desc] (reagent/as-element [react/view styles/web-view-error @@ -74,11 +90,30 @@ (let [domain-name (nth (re-find #"^\w+://(www\.)?([^/:]+)" url) 2)] (get (:inject-js browser-config) domain-name))) +(defn navigation [webview browser can-go-back? can-go-forward?] + [react/view styles/toolbar + [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-back browser]) + :disabled (not can-go-back?) + :style (when-not can-go-back? styles/disabled-button) + :accessibility-label :previou-page-button} + [react/view + [icons/icon :icons/arrow-left]]] + [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-forward browser]) + :disabled (not can-go-forward?) + :style (merge styles/forward-button + (when-not can-go-forward? styles/disabled-button)) + :accessibility-label :next-page-button} + [react/view + [icons/icon :icons/arrow-right]]] + [react/view {:flex 1}] + [react/touchable-highlight {:on-press #(.reload @webview)} + [icons/icon :icons/refresh]]]) + (views/defview browser [] (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]} [:get :browser/options] + {:keys [error? loading? url-editing? show-tooltip show-permission]} [:get :browser/options] rpc-url [:get :rpc-url] network-id [:get-network-id]] (let [can-go-back? (model/can-go-back? browser) @@ -86,19 +121,7 @@ url (model/get-current-url browser)] [react/view styles/browser [status-bar/status-bar] - [toolbar.view/toolbar {} - [toolbar.view/nav-button-with-count - (actions/close (fn [] - (when @webview - (.sendToBridge @webview "navigate-to-blank")) - (re-frame/dispatch [:navigate-back]) - (when error? - (re-frame/dispatch [:remove-browser browser-id]))))] - [toolbar-content url browser error? url-editing?] - [toolbar.view/actions [{:icon :icons/wallet - :icon-opts {:color :black - :accessibility-label :wallet-modal-button} - :handler #(re-frame/dispatch [:navigate-to-modal :wallet-modal])}]]] + [toolbar webview error? url browser browser-id url-editing?] [react/view components.styles/flex [components.webview-bridge/webview-bridge {:dapp? dapp? @@ -126,23 +149,8 @@ (when loading? [react/view styles/web-view-loading [components/activity-indicator {:animating true}]])] - [react/view styles/toolbar - [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-back browser]) - :disabled (not can-go-back?) - :style (when-not can-go-back? styles/disabled-button) - :accessibility-label :previou-page-button} - [react/view - [icons/icon :icons/arrow-left]]] - [react/touchable-highlight {:on-press #(re-frame/dispatch [:browser-nav-forward browser]) - :disabled (not can-go-forward?) - :style (merge styles/forward-button - (when-not can-go-forward? styles/disabled-button)) - :accessibility-label :next-page-button} - [react/view - [icons/icon :icons/arrow-right]]] - [react/view {:flex 1}] - [react/touchable-highlight {:on-press #(.reload @webview)} - [icons/icon :icons/refresh]]] + [navigation webview browser can-go-back? can-go-forward?] + [permissions.views/permissions-anim-panel browser show-permission] (when show-tooltip [tooltip/bottom-tooltip-info (if (= show-tooltip :secure) diff --git a/test/cljs/status_im/test/browser/events.cljs b/test/cljs/status_im/test/browser/events.cljs index 267b8e5a11..2a45f9c706 100644 --- a/test/cljs/status_im/test/browser/events.cljs +++ b/test/cljs/status_im/test/browser/events.cljs @@ -135,6 +135,12 @@ :permissions ["FAKE_PERMISSION"]}) nil nil]) + (re-frame/dispatch [:next-dapp-permission + {:dapp-name dapp-name + :index 0 + :requested-permissions ["FAKE_PERMISSION"] + :permissions-data "Data"}]) + (is (= {:dapp dapp-name :permissions []} (get @dapps-permissions dapp-name))) @@ -144,6 +150,14 @@ :permissions ["CONTACT_CODE"]}) nil nil]) + (re-frame/dispatch [:next-dapp-permission + {:dapp-name dapp-name + :index 0 + :requested-permissions ["CONTACT_CODE"] + :permissions-data {"CONTACT_CODE" "Data"}} + "CONTACT_CODE" + {"CONTACT_CODE" "Data"}]) + (is (= 1 (count @dapps-permissions))) (is (= {:dapp dapp-name @@ -177,6 +191,12 @@ :permissions ["CONTACT_CODE"]}) nil nil]) + (re-frame/dispatch [:next-dapp-permission + {:dapp-name dapp-name2 + :index 0 + :requested-permissions ["CONTACT_CODE" "FAKE_PERMISSION"] + :permissions-data "Data"}]) + (is (= 2 (count @dapps-permissions))) (is (= {:dapp dapp-name2