From d79d2e9d36873e60b5f321862db8e396744924ea Mon Sep 17 00:00:00 2001 From: flexsurfer Date: Mon, 23 Jan 2023 14:41:55 +0100 Subject: [PATCH] sanitize quo2 (#14859) --- src/quo2/components/code/snippet.cljs | 7 +- .../components/community/token_gating.cljs | 6 +- src/quo2/components/messages/author/view.cljs | 7 +- src/quo2/components/tags/tags.cljs | 130 +++++++++--------- src/react_native/clipboard.cljs | 10 ++ src/react_native/core.cljs | 11 ++ .../ui2/screens/chat/composer/input.cljs | 44 +++--- .../contexts/chat/messages/content/view.cljs | 13 +- .../contexts/quo_preview/messages/author.cljs | 6 +- 9 files changed, 124 insertions(+), 110 deletions(-) create mode 100644 src/react_native/clipboard.cljs diff --git a/src/quo2/components/code/snippet.cljs b/src/quo2/components/code/snippet.cljs index e09d160786..a81e1170f7 100644 --- a/src/quo2/components/code/snippet.cljs +++ b/src/quo2/components/code/snippet.cljs @@ -1,6 +1,5 @@ (ns quo2.components.code.snippet - (:require ["react-native" :as react-native] - [cljs-bean.core :as bean] + (:require [cljs-bean.core :as bean] [clojure.string :as string] [oops.core :as oops] [quo2.components.buttons.button :as button] @@ -168,8 +167,8 @@ :on-copy-press #(when on-copy-press (on-copy-press children))}) ;; Default props to adapt Highlighter for react-native. - :CodeTag react-native/View - :PreTag react-native/View + ;;:CodeTag react-native/View + ;;:PreTag react-native/View :show-line-numbers false :style #js {} :custom-style #js {:backgroundColor nil}} diff --git a/src/quo2/components/community/token_gating.cljs b/src/quo2/components/community/token_gating.cljs index 4a7956b7a6..afcf99e3b9 100644 --- a/src/quo2/components/community/token_gating.cljs +++ b/src/quo2/components/community/token_gating.cljs @@ -1,6 +1,5 @@ (ns quo2.components.community.token-gating - (:require [quo.react-native :as rn] - [quo2.components.avatars.channel-avatar :as channel-avatar] + (:require [quo2.components.avatars.channel-avatar :as channel-avatar] [quo2.components.buttons.button :as button] [quo2.components.icon :as icon] [quo2.components.info.information-box :as information-box] @@ -8,7 +7,8 @@ [quo2.components.tags.token-tag :as token-tag] [quo2.foundations.colors :as colors] [utils.i18n :as i18n] - [react-native.fast-image :as fast-image])) + [react-native.fast-image :as fast-image] + [react-native.core :as rn])) (def ^:private token-tag-horizontal-spacing 7) (def token-tag-vertical-spacing 5) diff --git a/src/quo2/components/messages/author/view.cljs b/src/quo2/components/messages/author/view.cljs index f64854b70a..39ffaccdc9 100644 --- a/src/quo2/components/messages/author/view.cljs +++ b/src/quo2/components/messages/author/view.cljs @@ -3,8 +3,7 @@ [quo2.components.icon :as icons] [quo2.components.markdown.text :as text] [quo2.components.messages.author.style :as style] - [react-native.core :as rn] - [status-im.utils.utils :as utils])) + [react-native.core :as rn])) (def middle-dot "ยท") @@ -35,7 +34,7 @@ profile-name])]))) (defn author - [{:keys [profile-name nickname chat-key ens-name time-str contact? verified? untrustworthy?]}] + [{:keys [profile-name nickname short-chat-key ens-name time-str contact? verified? untrustworthy?]}] [:f> (fn [] (let [ens? (-> ens-name string/blank? not) @@ -85,7 +84,7 @@ {:monospace true :size :paragraph-2 :style style/chat-key-text} - (utils/get-shortened-address chat-key)]) + short-chat-key]) (when-not ens? [text/text {:monospace true diff --git a/src/quo2/components/tags/tags.cljs b/src/quo2/components/tags/tags.cljs index 5bfb85f1d7..d563141487 100644 --- a/src/quo2/components/tags/tags.cljs +++ b/src/quo2/components/tags/tags.cljs @@ -1,11 +1,12 @@ (ns quo2.components.tags.tags (:require [reagent.core :as reagent] - [quo.react-native :as rn] [oops.core :refer [oget]] - [status-im.ui.components.react :as react] - [status-im.utils.core :as utils] [quo2.components.tags.tag :as tag] - [utils.number :as number-utils])) + [utils.number :as number-utils] + [react-native.core :as rn] + [react-native.masked-view :as masked-view] + [react-native.linear-gradient :as linear-gradient] + [utils.collection :as utils.collection])) (def default-tab-size 32) @@ -76,9 +77,9 @@ size default-tab-size} :as props}] (let [maybe-mask-wrapper (if fade-end? - [react/masked-view + [masked-view/masked-view {:mask-element (reagent/as-element - [react/linear-gradient + [linear-gradient/linear-gradient {:colors [:black :transparent] :locations [(get @fading :fade-end-percentage) 1] @@ -92,64 +93,65 @@ (conj maybe-mask-wrapper [rn/flat-list - (merge (dissoc props - :default-active - :fade-end-percentage - :fade-end? - :on-change - :scroll-on-press? - :size) - (when scroll-on-press? - {:initial-scroll-index (utils/first-index #(= @active-tab-id (:id %)) data)}) - {:ref #(reset! flat-list-ref %) - :extra-data (str @active-tab-id) - :horizontal true - :scroll-event-throttle scroll-event-throttle - :shows-horizontal-scroll-indicator false - :data data - :key-fn (comp str :id) - :on-scroll (fn [^js e] - (when fade-end? - (let [offset-x (oget e "nativeEvent.contentOffset.x") - content-width (oget e "nativeEvent.contentSize.width") - layout-width (oget e "nativeEvent.layoutMeasurement.width") - new-percentage (calculate-fade-end-percentage - {:offset-x offset-x - :content-width content-width - :layout-width layout-width - :max-fade-percentage fade-end-percentage})] - ;; Avoid unnecessary re-rendering. - (when (not= new-percentage (get @fading :fade-end-percentage)) - (swap! fading assoc :fade-end-percentage new-percentage)))) - (when on-scroll - (on-scroll e))) - :render-fn (fn [{:keys [id label resource]} index] - [rn/view - {:style {:margin-right (if (= size default-tab-size) 12 8) - :padding-right (when (= index (dec (count data))) - (get-in props [:style :padding-left]))}} - [tag/tag - {:id id - :size size - :active (= id @active-tab-id) - :resource resource - :blurred? blurred? - :icon-color icon-color - :disabled? disabled? - :label label - :type type - :labelled? labelled? - :on-press (fn [id] - (reset! active-tab-id id) - (when scroll-on-press? - (.scrollToIndex ^js @flat-list-ref - #js - {:animated true - :index index - :viewPosition 0.5})) - (when on-change - (on-change id)))} - label]])})]) + (merge + (dissoc props + :default-active + :fade-end-percentage + :fade-end? + :on-change + :scroll-on-press? + :size) + (when scroll-on-press? + {:initial-scroll-index (utils.collection/first-index #(= @active-tab-id (:id %)) data)}) + {:ref #(reset! flat-list-ref %) + :extra-data (str @active-tab-id) + :horizontal true + :scroll-event-throttle scroll-event-throttle + :shows-horizontal-scroll-indicator false + :data data + :key-fn (comp str :id) + :on-scroll (fn [^js e] + (when fade-end? + (let [offset-x (oget e "nativeEvent.contentOffset.x") + content-width (oget e "nativeEvent.contentSize.width") + layout-width (oget e "nativeEvent.layoutMeasurement.width") + new-percentage (calculate-fade-end-percentage + {:offset-x offset-x + :content-width content-width + :layout-width layout-width + :max-fade-percentage fade-end-percentage})] + ;; Avoid unnecessary re-rendering. + (when (not= new-percentage (get @fading :fade-end-percentage)) + (swap! fading assoc :fade-end-percentage new-percentage)))) + (when on-scroll + (on-scroll e))) + :render-fn (fn [{:keys [id label resource]} index] + [rn/view + {:style {:margin-right (if (= size default-tab-size) 12 8) + :padding-right (when (= index (dec (count data))) + (get-in props [:style :padding-left]))}} + [tag/tag + {:id id + :size size + :active (= id @active-tab-id) + :resource resource + :blurred? blurred? + :icon-color icon-color + :disabled? disabled? + :label label + :type type + :labelled? labelled? + :on-press (fn [id] + (reset! active-tab-id id) + (when scroll-on-press? + (.scrollToIndex ^js @flat-list-ref + #js + {:animated true + :index index + :viewPosition 0.5})) + (when on-change + (on-change id)))} + label]])})]) [rn/view {:style {:flex-direction :row}} (for [{:keys [label id resource]} data] ^{:key id} diff --git a/src/react_native/clipboard.cljs b/src/react_native/clipboard.cljs new file mode 100644 index 0000000000..d02b6204af --- /dev/null +++ b/src/react_native/clipboard.cljs @@ -0,0 +1,10 @@ +(ns react-native.clipboard + (:require ["@react-native-community/clipboard" :default Clipboard])) + +(defn set-string + [text] + (.setString ^js Clipboard text)) + +(defn get-string + [callback] + (.then (.getString ^js Clipboard) #(callback %))) diff --git a/src/react_native/core.cljs b/src/react_native/core.cljs index 24fe910d70..ac1d7b5d31 100644 --- a/src/react_native/core.cljs +++ b/src/react_native/core.cljs @@ -117,3 +117,14 @@ {:ease-in-ease-out (-> ^js layout-animation .-Presets .-easeInEaseOut) :linear (-> ^js layout-animation .-Presets .-linear) :spring (-> ^js layout-animation .-Presets .-spring)}) + +(def find-node-handle (.-findNodeHandle ^js react-native)) + +(defn selectable-text-input-manager + [] + (when (exists? (.-NativeModules ^js react-native)) + (.-RNSelectableTextInputManager ^js (.-NativeModules ^js react-native)))) + +(defonce selectable-text-input + (reagent/adapt-react-class + (.requireNativeComponent ^js react-native "RNSelectableTextInput"))) diff --git a/src/status_im/ui2/screens/chat/composer/input.cljs b/src/status_im/ui2/screens/chat/composer/input.cljs index 8b5219c2f9..17df38b6d4 100644 --- a/src/status_im/ui2/screens/chat/composer/input.cljs +++ b/src/status_im/ui2/screens/chat/composer/input.cljs @@ -1,22 +1,20 @@ (ns status-im.ui2.screens.chat.composer.input - (:require ["react-native" :as react-native] - [clojure.string :as string] + (:require [clojure.string :as string] [oops.core :as oops] - [quo.design-system.colors :as quo.colors] - [quo.react] - [quo.react-native :as rn] [quo2.foundations.colors :as colors] [re-frame.core :as re-frame] [reagent.core :as reagent] [status-im2.constants :as chat.constants] [status-im.chat.models.mentions :as mentions] [utils.i18n :as i18n] - [status-im.ui.components.react :as react] [utils.re-frame :as rf] - [status-im.utils.platform :as platform] - [status-im.utils.utils :as utils.utils] [utils.transforms :as transforms] - [quo2.foundations.typography :as typography])) + [quo2.foundations.typography :as typography] + [react-native.background-timer :as background-timer] + [react-native.platform :as platform] + [react-native.core :as rn] + [react-native.clipboard :as clipboard] + [quo.react :as quo.react])) (defonce input-texts (atom {})) (defonce input-text-content-heights (atom {})) @@ -94,7 +92,7 @@ (when platform/ios? (reset! timeout-id - (utils.utils/set-timeout + (background-timer/set-timeout #(rf/dispatch [::mentions/on-selection-change {:start start :end end} @@ -128,7 +126,7 @@ ;; happens during typing because it is not needed for mention ;; suggestions calculation (when (and platform/ios? @timeout-id) - (utils.utils/clear-timeout @timeout-id)) + (background-timer/clear-timeout @timeout-id)) (when platform/android? (reset! last-text-change (js/Date.now))) @@ -169,7 +167,7 @@ :min-height 34 :margin 0 :flex-shrink 1 - :color (:text-01 @quo.colors/theme) + :color (colors/theme-colors colors/neutral-100 colors/white) :margin-horizontal 20} (if platform/android? {:padding-vertical 8 @@ -195,7 +193,7 @@ :blur-on-submit false :auto-focus false :max-length chat.constants/max-text-size - :placeholder-text-color (:text-02 @quo.colors/theme) + :placeholder-text-color (colors/theme-colors colors/neutral-40 colors/white-opa-30) :placeholder (if cooldown-enabled? (i18n/label :cooldown/text-input-disabled) (i18n/label :t/type-a-message)) @@ -230,14 +228,6 @@ [rn/text-input props children]))) -(defn selectable-text-input-manager - [] - (when (exists? (.-NativeModules react-native)) - (.-RNSelectableTextInputManager ^js (.-NativeModules react-native)))) - -(defonce rn-selectable-text-input - (reagent/adapt-react-class (.requireNativeComponent react-native "RNSelectableTextInput"))) - (declare first-level-menu-items second-level-menu-items) (defn update-input-text @@ -269,24 +259,24 @@ ;https://lightrun.com/answers/facebook-react-native-textinput-controlled-selection-broken-on-both-ios-and-android ;use native invoke instead! do not use setNativeProps! e.g. (.setNativeProps ^js text-input (clj->js ;{:selection {:start selection-start :end selection-end}})) - (let [manager (selectable-text-input-manager)] + (let [manager (rn/selectable-text-input-manager)] (oops/ocall manager :setSelection text-input-handle selection-start selection-end))) (def first-level-menus {:cut (fn [{:keys [content] :as params}] (let [new-text (calculate-input-text params "")] - (react/copy-to-clipboard content) + (clipboard/set-string content) (update-input-text params new-text))) :copy-to-clipboard (fn [{:keys [content]}] - (react/copy-to-clipboard content)) + (clipboard/set-string content)) :paste (fn [params] (let [callback (fn [paste-content] (let [content (string/trim paste-content) new-text (calculate-input-text params content)] (update-input-text params new-text)))] - (react/get-from-clipboard callback))) + (clipboard/get-string callback))) :biu (fn [{:keys [first-level text-input-handle menu-items selection-start selection-end]}] @@ -340,7 +330,7 @@ menu-items (reagent/atom first-level-menu-items) first-level (reagent/atom true) selection-event (atom nil) - manager (selectable-text-input-manager)] + manager (rn/selectable-text-input-manager)] (reagent/create-class {:component-did-mount (fn [this] @@ -395,6 +385,6 @@ :style (dissoc style :margin-horizontal) :on-selection-change on-selection-change :on-selection on-selection})] - [rn-selectable-text-input {:menuItems @menu-items :style style} + [rn/selectable-text-input {:menuItems @menu-items :style style} [rn/text-input props children]]))}))) diff --git a/src/status_im2/contexts/chat/messages/content/view.cljs b/src/status_im2/contexts/chat/messages/content/view.cljs index 82f1f5d1bc..cfccd555da 100644 --- a/src/status_im2/contexts/chat/messages/content/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/view.cljs @@ -16,7 +16,8 @@ [utils.re-frame :as rf] [status-im.ui2.screens.chat.messages.message :as old-message] [status-im2.common.not-implemented :as not-implemented] - [utils.datetime :as datetime])) + [utils.datetime :as datetime] + [status-im.utils.utils :as utils])) (defn avatar [{:keys [response-to last-in-group? pinned quoted-message from]}] @@ -41,11 +42,11 @@ (let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity from])) {:keys [ens-verified added?]} (rf/sub [:contacts/contact-by-address from])] [quo/author - {:profile-name display-name - :chat-key from - :time-str (datetime/timestamp->time timestamp) - :contact? added? - :verified? ens-verified}]))) + {:profile-name display-name + :short-chat-key (utils/get-shortened-address from) + :time-str (datetime/timestamp->time timestamp) + :contact? added? + :verified? ens-verified}]))) (defn system-message-content [{:keys [content-type quoted-message] :as message-data}] diff --git a/src/status_im2/contexts/quo_preview/messages/author.cljs b/src/status_im2/contexts/quo_preview/messages/author.cljs index ac9bcd5c6d..a116beff31 100644 --- a/src/status_im2/contexts/quo_preview/messages/author.cljs +++ b/src/status_im2/contexts/quo_preview/messages/author.cljs @@ -4,7 +4,8 @@ [quo2.foundations.colors :as colors] [react-native.core :as rn] [reagent.core :as reagent] - [status-im2.contexts.quo-preview.preview :as preview])) + [status-im2.contexts.quo-preview.preview :as preview] + [status-im.utils.utils :as utils])) (def descriptor [{:label "Profile name" @@ -39,7 +40,8 @@ [] (let [state (reagent/atom {:profile-name "Alisher Yakupov" :nickname "" - :chat-key "zQ3ssgRy5TtB47MMiMKMKaGyaawkCgMqqbrnAUYrZJ1sgt5N" + :short-chat-key (utils/get-shortened-address + "zQ3ssgRy5TtB47MMiMKMKaGyaawkCgMqqbrnAUYrZJ1sgt5N") :time-str "09:30" :ens-name "" :contact? false