diff --git a/config/default.json b/config/default.json index 5b200c2d30d239efa9f85df2ffaf8771db30da02..4963527dd3423b5c8f7c18caab48cb608d1fcb19 100644 --- a/config/default.json +++ b/config/default.json @@ -4,7 +4,7 @@ "helmet": { "directives": { "childSrc": "'self' 3speak.online emb.d.tube player.twitch.tv www.youtube.com staticxx.facebook.com w.soundcloud.com player.vimeo.com", - "connectSrc": "https://images.hive.blog 'self' hive.blog https://api.hive.blog api.blocktrades.us https://anyx.io", + "connectSrc": "https://images.hive.blog 'self' hive.blog https://api.hive.blog api.blocktrades.us https://anyx.io https://hivesigner.com", "defaultSrc": "tpc.googlesyndication.com 'self' img.3speakcontent.online emb.d.tube www.youtube.com staticxx.facebook.com player.vimeo.com *.streamrail.com", "fontSrc": "data: fonts.gstatic.com", "frameAncestors": "'none'", diff --git a/package.json b/package.json index e07deff4c5d1c27cc1e59d4bc9b2c212e8e4ad5c..24bf81777a53bccc78165d3308eeb6f684004466 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "cpu-stat": "2.0.1", "diff-match-patch": "1.0.4", "disk-stat": "1.0.4", + "hivesigner": "^3.2.0", "humanize-number": "0.0.2", "intl": "1.2.5", "iso": "5.2.0", diff --git a/src/app/ResolveRoute.js b/src/app/ResolveRoute.js index df4f2add29cc45c13a552a7681afb49032f117b4..2437c244d1d1d5dd1d40345f9376a131192a8890 100644 --- a/src/app/ResolveRoute.js +++ b/src/app/ResolveRoute.js @@ -43,6 +43,7 @@ export default function resolveRoute(path) { // general functions if (path === '/login.html') return { page: 'Login' }; + if (path === '/login/hivesigner') return { page: 'HiveSignerLogin' }; if (path === '/submit.html') return { page: 'SubmitPost' }; if (path === '/communities') return { page: 'Communities' }; if (path === '/tags') return { page: 'Tags' }; diff --git a/src/app/RootRoute.js b/src/app/RootRoute.js index 6ccb44ad635e7a7e367b5111f28a1c7597e37d99..1c634375e64aac674b7c9a13531101ac531bb98a 100644 --- a/src/app/RootRoute.js +++ b/src/app/RootRoute.js @@ -30,6 +30,10 @@ export default { //require.ensure([], (require) => { cb(null, [require('app/components/pages/Login')]); //}); + } else if (route.page === 'HiveSignerLogin') { + //require.ensure([], (require) => { + cb(null, [require('app/components/pages/HiveSignerLogin')]); + //}); } else if (route.page === 'Privacy') { //require.ensure([], (require) => { cb(null, [require('app/components/pages/Privacy')]); diff --git a/src/app/assets/images/hivesigner.svg b/src/app/assets/images/hivesigner.svg new file mode 100644 index 0000000000000000000000000000000000000000..1b38215e5f2cbeb0a7c39408df939cecfbc7c2d1 --- /dev/null +++ b/src/app/assets/images/hivesigner.svg @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="250mm" + height="50mm" + viewBox="0 0 250 50" + version="1.1" + id="svg8" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="hivesigner.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.35" + inkscape:cx="-117.14286" + inkscape:cy="560" + inkscape:document-units="mm" + inkscape:current-layer="g995" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1023" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-247)"> + <g + id="g995" + transform="translate(2.381251)"> + <g + id="g1043" + transform="translate(1.8520845,-1.8649999e-6)"> + <g + id="g637" + style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1" + transform="matrix(0.32014583,0,0,0.32014583,16.879399,251.03045)"> + <g + id="g635" + style="fill:#e31337;fill-opacity:1"> + <path + d="M 98.541667,69.923306 V 45.887017 H 0 V 0 H 110 V 22.943509 H 98.541667 V 11.471754 H 11.458333 V 34.415263 H 110 v 37.340478 c -0.18517,18.239539 -10.382232,33.200889 -27.247234,45.104989 -5.956567,4.20442 -12.346375,7.7265 -18.75154,10.59653 -2.257779,1.01167 -4.362872,1.87137 -6.261489,2.58208 -1.170273,0.43806 -2.105573,0.76041 -2.522569,0.89083 L 54.99392,131 54.770964,130.9292 c -0.467103,-0.14823 -1.351404,-0.45331 -2.518442,-0.89038 -1.898774,-0.71112 -4.002941,-1.57072 -6.259897,-2.58226 C 39.58819,124.58617 33.199766,121.06429 27.244225,116.8601 10.54075,105.06867 0.37991151,90.277944 0.0104348,72.272052 H 0 v -14.91328 h 11.458333 v 12.564534 c 0,13.829856 7.221147,25.398143 19.608216,34.855994 4.574183,3.49252 9.611145,6.50237 14.833332,9.04511 3.4621,1.68573 6.579291,2.96581 9.101659,3.85697 2.519577,-0.88982 5.638459,-2.17053 9.10069,-3.85634 5.221824,-2.5426 10.258741,-5.55255 14.832882,-9.04517 12.38688,-9.458104 19.606555,-21.026716 19.606555,-34.856564 z" + id="path633" + style="fill:#e31337;fill-opacity:1" + inkscape:connector-curvature="0" /> + </g> + </g> + <g + aria-label="hivesigner" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28888893px;line-height:1.25;font-family:'Circular Pro Bold';-inkscape-font-specification:'Circular Pro Bold, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + id="text876" + transform="translate(0,-1.5e-5)"> + <path + d="m 71.710308,280.6131 v -23.50175 h 4.326351 v 8.85871 q 0.74483,-0.8716 1.901693,-1.29949 1.17271,-0.44372 2.408811,-0.44372 1.965082,0 3.327962,0.87161 1.36288,0.85576 1.98093,2.25033 0.633897,1.39458 0.633897,3.20118 v 10.06313 h -4.310503 v -9.3183 q 0,-1.42627 -0.74483,-2.29787 -0.728982,-0.87161 -2.218641,-0.87161 -1.331185,0 -2.123557,0.87161 -0.776525,0.8716 -0.855762,2.23448 v 9.38169 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path960" + inkscape:connector-curvature="0" /> + <path + d="m 90.156727,259.42507 q 0,-1.10932 0.776525,-1.90169 0.792372,-0.79237 1.885845,-0.79237 1.109321,0 1.885845,0.79237 0.776525,0.77652 0.776525,1.90169 0,1.07763 -0.776525,1.85415 -0.776524,0.77653 -1.885845,0.77653 -1.093473,0 -1.885845,-0.77653 -0.776525,-0.77652 -0.776525,-1.85415 z m 0.507118,21.18803 v -15.97422 h 4.326351 v 15.97422 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path962" + inkscape:connector-curvature="0" /> + <path + d="m 97.620871,264.63888 h 4.738389 l 3.96186,10.71287 3.80338,-10.71287 h 4.54822 l -6.19635,15.97422 h -4.32635 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path964" + inkscape:connector-curvature="0" /> + <path + d="m 115.59186,272.5626 q 0,-1.85415 0.64975,-3.45474 0.64974,-1.60059 1.72737,-2.66237 1.09347,-1.07763 2.5039,-1.67983 1.42627,-0.6022 2.96347,-0.6022 3.69245,0 5.78431,2.21864 2.10771,2.20279 2.10771,6.05372 0,0.26941 -0.0159,0.58635 -0.0158,0.31695 -0.0317,0.52297 -0.0159,0.20602 -0.0159,0.22186 h -11.426 q 0.0634,1.5689 1.2361,2.59898 1.17271,1.03009 2.78915,1.03009 2.7416,0 3.62906,-2.42466 l 3.61322,1.06178 q -0.64975,2.20279 -2.55144,3.64491 -1.90169,1.42627 -4.72254,1.42627 -1.64813,0 -3.13779,-0.58636 -1.48966,-0.58635 -2.63067,-1.64813 -1.12517,-1.07763 -1.80661,-2.70991 -0.6656,-1.63229 -0.6656,-3.59737 z m 4.3422,-1.74322 h 7.1472 q -0.0475,-1.31534 -0.95085,-2.23449 -0.9033,-0.91915 -2.63067,-0.91915 -1.5689,0 -2.53559,0.96669 -0.95085,0.9667 -1.03009,2.18695 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path966" + inkscape:connector-curvature="0" /> + <path + d="m 133.35684,276.15997 3.7083,-0.80822 q 0.0792,1.03008 0.82407,1.74322 0.76068,0.69728 2.09186,0.69728 1.01424,0 1.55305,-0.45957 0.55466,-0.45958 0.55466,-1.14102 0,-1.2044 -1.71152,-1.55305 l -2.10771,-0.49127 q -2.23449,-0.49127 -3.35966,-1.75906 -1.12517,-1.2678 -1.12517,-3.01102 0,-2.1711 1.71153,-3.69245 1.71152,-1.52135 4.26296,-1.52135 1.29949,0 2.36127,0.31695 1.07762,0.31694 1.75906,0.80821 0.68144,0.47543 1.15687,1.10933 0.47542,0.63389 0.69728,1.22025 0.22187,0.57051 0.28526,1.14101 l -3.59737,0.82407 q -0.11093,-0.85576 -0.76068,-1.48966 -0.6339,-0.64974 -1.87,-0.64974 -0.85576,0 -1.45796,0.45957 -0.58636,0.44373 -0.58636,1.12517 0,0.57051 0.39619,0.935 0.39619,0.36449 1.06178,0.49127 l 2.26618,0.49127 q 2.29788,0.47542 3.51813,1.79076 1.22026,1.29949 1.22026,3.1061 0,0.99839 -0.39619,1.93339 -0.38034,0.91915 -1.12517,1.67983 -0.74483,0.74482 -1.96508,1.18855 -1.20441,0.45958 -2.70991,0.45958 -1.37873,0 -2.51975,-0.34864 -1.12516,-0.3328 -1.85415,-0.85577 -0.71313,-0.53881 -1.2361,-1.22025 -0.50711,-0.68144 -0.74483,-1.29949 -0.23771,-0.6339 -0.3011,-1.22025 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path968" + inkscape:connector-curvature="0" /> + <path + d="m 149.17259,259.42507 q 0,-1.10932 0.77652,-1.90169 0.79238,-0.79237 1.88585,-0.79237 1.10932,0 1.88584,0.79237 0.77653,0.77652 0.77653,1.90169 0,1.07763 -0.77653,1.85415 -0.77652,0.77653 -1.88584,0.77653 -1.09347,0 -1.88585,-0.77653 -0.77652,-0.77652 -0.77652,-1.85415 z m 0.50712,21.18803 v -15.97422 h 4.32635 v 15.97422 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path970" + inkscape:connector-curvature="0" /> + <path + d="m 157.4925,281.48471 3.88262,-1.03009 q 0.22186,1.34704 1.22025,2.1711 1.01424,0.83992 2.51974,0.83992 4.24712,0 4.24712,-4.43729 v -1.17271 q -0.53881,0.87161 -1.67983,1.45797 -1.14102,0.58635 -2.75745,0.58635 -3.20119,0 -5.32474,-2.20279 -2.10771,-2.20279 -2.10771,-5.56245 0,-2.10771 0.935,-3.88262 0.93499,-1.77492 2.64652,-2.8367 1.71152,-1.06177 3.85093,-1.06177 1.75906,0 2.90008,0.63389 1.15686,0.61805 1.63228,1.5372 v -1.88584 h 4.16788 v 14.24685 q 0,1.34703 -0.3011,2.55143 -0.28526,1.20441 -0.935,2.28204 -0.6339,1.07762 -1.60059,1.85415 -0.95085,0.79237 -2.37712,1.2361 -1.42627,0.45957 -3.16949,0.45957 -3.15364,0 -5.27719,-1.69567 -2.10771,-1.67983 -2.4722,-4.08864 z m 4.34219,-9.34999 q 0,1.85415 1.06178,2.96347 1.07763,1.09347 2.77331,1.09347 1.66398,0 2.70991,-1.10932 1.04593,-1.10932 1.04593,-2.94762 0,-1.80661 -1.07763,-2.90008 -1.07762,-1.10932 -2.67821,-1.10932 -1.64814,0 -2.74161,1.10932 -1.09348,1.09347 -1.09348,2.90008 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path972" + inkscape:connector-curvature="0" /> + <path + d="m 178.01493,280.6131 v -15.97422 h 4.19957 v 1.98093 q 0.69729,-1.17271 1.94923,-1.77491 1.2678,-0.61805 2.64653,-0.61805 2.83669,0 4.3105,1.77491 1.47381,1.75907 1.47381,4.54821 v 10.06313 h -4.3105 v -9.3183 q 0,-1.42627 -0.74483,-2.29787 -0.72898,-0.87161 -2.21864,-0.87161 -1.37873,0 -2.18695,0.935 -0.79237,0.93499 -0.79237,2.36126 v 9.19152 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path974" + inkscape:connector-curvature="0" /> + <path + d="m 195.77991,272.5626 q 0,-1.85415 0.64974,-3.45474 0.64975,-1.60059 1.72737,-2.66237 1.09348,-1.07763 2.5039,-1.67983 1.42627,-0.6022 2.96347,-0.6022 3.69245,0 5.78431,2.21864 2.10771,2.20279 2.10771,6.05372 0,0.26941 -0.0158,0.58635 -0.0159,0.31695 -0.0317,0.52297 -0.0159,0.20602 -0.0159,0.22186 h -11.426 q 0.0634,1.5689 1.2361,2.59898 1.17271,1.03009 2.78915,1.03009 2.74161,0 3.62906,-2.42466 l 3.61322,1.06178 q -0.64975,2.20279 -2.55144,3.64491 -1.90169,1.42627 -4.72254,1.42627 -1.64813,0 -3.13779,-0.58636 -1.48966,-0.58635 -2.63067,-1.64813 -1.12517,-1.07763 -1.80661,-2.70991 -0.66559,-1.63229 -0.66559,-3.59737 z m 4.34219,-1.74322 h 7.1472 q -0.0475,-1.31534 -0.95085,-2.23449 -0.9033,-0.91915 -2.63067,-0.91915 -1.5689,0 -2.53559,0.96669 -0.95085,0.9667 -1.03009,2.18695 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path976" + inkscape:connector-curvature="0" /> + <path + d="m 214.90776,280.6131 v -15.97422 h 4.19957 v 2.37712 q 0.34864,-0.74483 0.9033,-1.2678 0.57051,-0.53881 1.22026,-0.77652 0.66559,-0.25356 1.2361,-0.34865 0.58635,-0.11093 1.17271,-0.11093 0.38033,0 1.01423,0.0634 v 4.35805 q -0.64974,-0.12678 -1.29949,-0.12678 -0.87161,0 -1.58474,0.23771 -0.69729,0.22186 -1.29949,0.72898 -0.58636,0.49127 -0.91915,1.39457 -0.31695,0.88746 -0.31695,2.13941 v 7.30567 z" + style="font-size:32.45555496px;fill:#1a1a1a;stroke-width:0.26458332" + id="path978" + inkscape:connector-curvature="0" /> + </g> + </g> + </g> + <flowRoot + xml:space="preserve" + id="flowRoot935" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:42.66666794px;line-height:1.25;font-family:'Circular Pro Bold';-inkscape-font-specification:'Circular Pro Bold, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none" + transform="matrix(0.26458333,0,0,0.26458333,0,247)"><flowRegion + id="flowRegion937"><rect + id="rect939" + width="1205.7142" + height="660" + x="-97.14286" + y="-308.16647" /></flowRegion><flowPara + id="flowPara941"></flowPara></flowRoot> </g> +</svg> diff --git a/src/app/client_config.js b/src/app/client_config.js index 98cce1f40a89b366ce6557e5631821acaac26210..ec16b007639ac8bc69622ec83d3a4e0d87bdb76c 100644 --- a/src/app/client_config.js +++ b/src/app/client_config.js @@ -9,6 +9,7 @@ export const APP_ICON = 'hive'; // vars. client should read $STM_Config, server should read config package. export const APP_URL = 'https://hive.blog'; export const APP_DOMAIN = 'hive.blog'; +export const HIVE_SIGNER_APP = 'hive.blog'; export const LIQUID_TOKEN = 'Hive'; // sometimes it's impossible to use html tags to style coin name, hence usage of _UPPERCASE modifier export const LIQUID_TOKEN_UPPERCASE = 'HIVE'; diff --git a/src/app/components/modules/LoginForm.jsx b/src/app/components/modules/LoginForm.jsx index 3baa0018d9068f3ee2a698b1330b44c2743a465f..7a9d9df3450b43c7485457b4b4ac66c44e1fe1a1 100644 --- a/src/app/components/modules/LoginForm.jsx +++ b/src/app/components/modules/LoginForm.jsx @@ -16,6 +16,8 @@ import { APP_URL } from 'app/client_config'; import { PrivateKey, PublicKey } from '@hiveio/hive-js/lib/auth/ecc'; import { SIGNUP_URL } from 'shared/constants'; import PdfDownload from 'app/components/elements/PdfDownload'; +import { hiveSignerClient } from 'app/utils/HiveSigner'; +import { getQueryStringParams } from 'app/utils/Links'; class LoginForm extends Component { static propTypes = { @@ -32,6 +34,7 @@ class LoginForm extends Component { super(); const cryptoTestResult = runTests(); let cryptographyFailure = false; + const isHiveSigner = false; this.SignUp = this.SignUp.bind(this); if (cryptoTestResult !== undefined) { console.error( @@ -40,7 +43,7 @@ class LoginForm extends Component { ); cryptographyFailure = true; } - this.state = { cryptographyFailure }; + this.state = { cryptographyFailure, isHiveSigner }; this.usernameOnChange = e => { const value = e.target.value.toLowerCase(); this.state.username.props.onChange(value); @@ -64,6 +67,10 @@ class LoginForm extends Component { this.initForm(props); } + componentWillMount() { + this.loginWithHiveSigner(); + } + componentDidMount() { if (this.refs.username && !this.refs.username.value) this.refs.username.focus(); @@ -118,6 +125,46 @@ class LoginForm extends Component { saveLogin.props.onChange(saveLoginDefault); // change UI }; + onClickHiveSignerBtn = () => { + const { saveLogin } = this.state; + const { afterLoginRedirectToWelcome } = this.props; + hiveSignerClient.login({ + state: JSON.stringify({ + lastPath: window.location.pathname, + saveLogin: saveLogin.value, + afterLoginRedirectToWelcome, + }), + }); + }; + + loginWithHiveSigner = () => { + const path = window.location.pathname; + if (path === '/login/hivesigner') { + this.setState({ + isHiveSigner: true, + }); + const params = getQueryStringParams(window.location.search); + const { username, access_token, expires_in, state } = params; + const { + saveLogin, + afterLoginRedirectToWelcome, + lastPath, + } = JSON.parse(state); + const { reallySubmit, loginBroadcastOperation } = this.props; + const data = { + username, + access_token, + expires_in, + saveLogin, + loginBroadcastOperation, + useHiveSigner: true, + lastPath, + }; + console.log('login:hivesigner', data); + reallySubmit(data, afterLoginRedirectToWelcome); + } + }; + render() { if (!process.env.BROWSER) { return ( @@ -182,7 +229,9 @@ class LoginForm extends Component { msg, } = this.props; const { username, password, useKeychain, saveLogin } = this.state; - const { submitting, valid, handleSubmit } = this.state.login; + const { valid, handleSubmit } = this.state.login; + const submitting = + this.state.login.submitting || this.state.isHiveSigner; const { usernameOnChange, onCancel /*qrReader*/ } = this; const disabled = submitting || !valid; const opType = loginBroadcastOperation @@ -462,13 +511,35 @@ class LoginForm extends Component { </form> ); - return ( - <div className="LoginForm row"> + const moreLoginMethods = ( + <div className="row buttons"> <div className="column"> - {message} - {showLoginWarning ? loginWarningTitleText : titleText} - {showLoginWarning ? loginWarningForm : form} + <a + id="btn-hivesigner" + className="button" + onClick={this.onClickHiveSignerBtn} + disabled={submitting} + > + <img src="/images/hivesigner.svg" /> + </a> + </div> + </div> + ); + + return ( + <div className="LoginForm"> + <div className="row"> + <div className="column"> + {message} + {showLoginWarning ? loginWarningTitleText : titleText} + {showLoginWarning ? loginWarningForm : form} + </div> + </div> + <div className="divider"> + <span>{tt('loginform_jsx.more_login_methods')}</span> </div> + <br /> + {moreLoginMethods} </div> ); } @@ -607,7 +678,16 @@ export default connect( } }, reallySubmit: ( - { username, password, saveLogin, loginBroadcastOperation }, + { + username, + password, + saveLogin, + loginBroadcastOperation, + access_token, + expires_in, + useHiveSigner, + lastPath, + }, afterLoginRedirectToWelcome ) => { const { type } = loginBroadcastOperation @@ -620,6 +700,10 @@ export default connect( userActions.usernamePasswordLogin({ username, password, + access_token, + expires_in, + lastPath, + useHiveSigner, saveLogin, afterLoginRedirectToWelcome, }) diff --git a/src/app/components/modules/LoginForm.scss b/src/app/components/modules/LoginForm.scss index 8d696a6c74bb4edf8a0028b53a9e42c3e7913c17..f2e03ff1b9f2bf6e1e585adffa6c7486ea74c4b8 100644 --- a/src/app/components/modules/LoginForm.scss +++ b/src/app/components/modules/LoginForm.scss @@ -7,6 +7,9 @@ form { margin-top: 1.5rem; } + .buttons { + text-align: center; + } } .pdf-download { margin-top: 1em; @@ -23,14 +26,14 @@ padding-top: 1rem; padding-bottom: 1rem; font-size: 1.2rem; - text-transform: none; + text-transform: none; } .button.hollow { border: 1px solid #ddd; color: $color-hive-black; transition: 0.2s all ease-in-out; @include font-size(16px); - + &:hover { border: 1px solid $color-hive-red-dark; color: $color-hive-red-dark; @@ -52,3 +55,35 @@ .LoginForm__save-login { margin-top: 0.5rem; } + +.divider{ + display: flex; + align-items: center; + font-size: 14px; +} +.divider::before,.divider::after{ + content: ''; + flex: 1; + height: 1px; + background: #ccc; +} +.divider::before{ + margin-right: 10px; +} +.divider::after{ + margin-left: 10px; +} + +#btn-hivesigner { + color: #fff; + border-color: #d1d5da; + background: #d1d5da; + + &:hover { + background: #A6A6A6; + } + + img { + width: 140px; + } +} diff --git a/src/app/components/pages/HiveSignerLogin.jsx b/src/app/components/pages/HiveSignerLogin.jsx new file mode 100644 index 0000000000000000000000000000000000000000..b34a93b7213ea27bef5fce1a1b44adb953ccaed5 --- /dev/null +++ b/src/app/components/pages/HiveSignerLogin.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import LoginForm from 'app/components/modules/LoginForm'; +import tt from 'counterpart'; + +class HiveSignerLogin extends React.Component { + render() { + if (!process.env.BROWSER) { + // don't render this page on the server + return ( + <div className="row"> + <div className="column">{tt('g.loading')}..</div> + </div> + ); + } + return ( + <div className="Login row"> + <div className="column"> + <LoginForm /> + </div> + </div> + ); + } +} + +module.exports = { + path: 'login/hivesigner', + component: HiveSignerLogin, +}; diff --git a/src/app/locales/en.json b/src/app/locales/en.json index 2ce7114f51eddbac12cd893871f5c7c369027653..95f88dc4c69851daaaab9831db04d55f5e105c21 100644 --- a/src/app/locales/en.json +++ b/src/app/locales/en.json @@ -681,7 +681,8 @@ "Open my Hive Wallet to access and view my posting key", "join_our": "Join our", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "more login methods" }, "chainvalidation_js": { "account_name_should_not_be_empty": "Account name should not be empty.", diff --git a/src/app/locales/es.json b/src/app/locales/es.json index 181d104dc4ec07f5a865a4957879c0a2bb7e19fe..31453b23ad847f6302d251325af459be0ba5c37b 100644 --- a/src/app/locales/es.json +++ b/src/app/locales/es.json @@ -587,7 +587,8 @@ "returning_users": "Inicia sesion", "join_our": "Únete a nuestro", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "más métodos de inicio de sesión" }, "chainvalidation_js": { "account_name_should": "El nombre de la cuenta deberÃa", diff --git a/src/app/locales/fr.json b/src/app/locales/fr.json index 948d04c2cb943f4cc2aa2f083a1cd2227372de3c..2b97038ada9ae4e46a06fed135be7fb9364c5f46 100644 --- a/src/app/locales/fr.json +++ b/src/app/locales/fr.json @@ -614,7 +614,8 @@ "returning_users": "Utilisateurs de retour: ", "join_our": "Rejoignez notre", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "plus de méthodes de connexion" }, "chainvalidation_js": { "account_name_should": "Le nom du compte doit ", diff --git a/src/app/locales/it.json b/src/app/locales/it.json index 83dbb5dcf5178826521b141849786cbdbbba885a..5e0a14c559f93c6887b9fa8aba0dad82320eb5d3 100644 --- a/src/app/locales/it.json +++ b/src/app/locales/it.json @@ -593,7 +593,8 @@ "returning_users": "Utenti di ritorno:", "join_our": "Unisciti al nostro", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "più metodi di accesso" }, "chainvalidation_js": { "account_name_should": "Il nome account", diff --git a/src/app/locales/ja.json b/src/app/locales/ja.json index c04b2f72f28c81ef53747931b3749cb5a728f96d..50cc7f0259e0f0915dc134ca688714bbbabd8b17 100644 --- a/src/app/locales/ja.json +++ b/src/app/locales/ja.json @@ -593,7 +593,8 @@ "returning_users": "å†", "join_our": "", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "ãã®ä»–ã®ãƒã‚°ã‚¤ãƒ³æ–¹æ³•" }, "chainvalidation_js": { "account_name_should": "アカウントå", diff --git a/src/app/locales/ko.json b/src/app/locales/ko.json index 5f338219c139b424f763b39bede55ef06e1a1b1f..a68d98dab3032c25e0f041df81cc9a74005ac852 100644 --- a/src/app/locales/ko.json +++ b/src/app/locales/ko.json @@ -589,7 +589,8 @@ "returning_users": "Returning Users: ", "join_our": "Join our", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "ë” ë§Žì€ ë¡œê·¸ì¸ ë°©ë²•" }, "chainvalidation_js": { "account_name_should": "Account name should ", diff --git a/src/app/locales/pl.json b/src/app/locales/pl.json index 0367975d4640f919131db1c83e80bda6f6f83cb1..b065941833f7af006f1af81a8a927782ce718bda 100644 --- a/src/app/locales/pl.json +++ b/src/app/locales/pl.json @@ -675,7 +675,8 @@ "Otwórz mój Portfel Hive, żeby uzyskać dostÄ™p i zobaczyć klucz do publikowania", "join_our": "Dołącz do", "sign_transfer": "Podpisz, aby dokoÅ„czyć przelew", - "use_keychain": "Użyj rozszerzenia Hive Keychain" + "use_keychain": "Użyj rozszerzenia Hive Keychain", + "more_login_methods": "wiÄ™cej metod logowania" }, "chainvalidation_js": { "account_name_should_not_be_empty": diff --git a/src/app/locales/ru.json b/src/app/locales/ru.json index ac7de0cb3a392bd7c20e7dbc279aa9061418ebca..9d1df1b24abef1c0ac321b8c8506a01157d5a84d 100644 --- a/src/app/locales/ru.json +++ b/src/app/locales/ru.json @@ -612,7 +612,8 @@ "returning_users": "ВернувшиеÑÑ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ð¸: ", "join_our": "ПриÑоединÑйтеÑÑŒ к нашему", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "больше методов входа" }, "chainvalidation_js": { "account_name_should": "Ð˜Ð¼Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚Ð° должно быть ", diff --git a/src/app/locales/zh.json b/src/app/locales/zh.json index 856ff7b44fa29ecb65a6a5f9e4ed497731be6181..8d3fcc3026d8808787539294ab3193419fa4afb7 100644 --- a/src/app/locales/zh.json +++ b/src/app/locales/zh.json @@ -540,7 +540,8 @@ "returning_users": "返回用户:", "join_our": "åŠ å…¥æˆ‘ä»¬", "sign_transfer": "Sign to complete transfer", - "use_keychain": "Use keychain extension" + "use_keychain": "Use keychain extension", + "more_login_methods": "更多登录方法" }, "chainvalidation_js": { "account_name_should": "叿ˆ·å称应该", diff --git a/src/app/redux/TransactionSaga.js b/src/app/redux/TransactionSaga.js index 8a169aaa8601879db08d11c322726a66ab58ea38..3e0375f3be9a2a65a760fe03187f24eb7887e33e 100644 --- a/src/app/redux/TransactionSaga.js +++ b/src/app/redux/TransactionSaga.js @@ -17,6 +17,11 @@ import { DEBT_TICKER } from 'app/client_config'; import { serverApiRecordEvent } from 'app/utils/ServerApiClient'; import { isLoggedInWithKeychain } from 'app/utils/HiveKeychain'; import { callBridge } from 'app/utils/steemApi'; +import { + isLoggedInWithHiveSigner, + hiveSignerClient, + sendOperationsWithHiveSigner, +} from 'app/utils/HiveSigner'; export const transactionWatches = [ takeEvery(transactionActions.BROADCAST_OPERATION, broadcastOperation), @@ -116,7 +121,7 @@ export function* broadcastOperation({ return; } try { - if (!isLoggedInWithKeychain()) { + if (!isLoggedInWithKeychain() && !isLoggedInWithHiveSigner()) { if (!keys || keys.length === 0) { payload.keys = []; // user may already be logged in, or just enterend a signing passowrd or wif @@ -278,20 +283,7 @@ function* broadcastPayload({ broadcastedEvent(); }, 2000); } else { - if (!isLoggedInWithKeychain()) { - broadcast.send( - { extensions: [], operations }, - keys, - err => { - if (err) { - reject(err); - } else { - broadcastedEvent(); - resolve(); - } - } - ); - } else { + if (isLoggedInWithKeychain()) { const authType = needsActiveAuth ? 'active' : 'posting'; window.hive_keychain.requestBroadcast( username, @@ -306,6 +298,46 @@ function* broadcastPayload({ } } ); + } else if (isLoggedInWithHiveSigner()) { + if (!needsActiveAuth) { + hiveSignerClient.broadcast( + operations, + (err, result) => { + if (err) { + reject(err.error_description); + } else { + broadcastedEvent(); + resolve(); + } + } + ); + } else { + sendOperationsWithHiveSigners( + operations, + {}, + (err, result) => { + if (err) { + reject(err.error_description); + } else { + broadcastedEvent(); + resolve(); + } + } + ); + } + } else { + broadcast.send( + { extensions: [], operations }, + keys, + err => { + if (err) { + reject(err); + } else { + broadcastedEvent(); + resolve(); + } + } + ); } } }); diff --git a/src/app/redux/UserSaga.js b/src/app/redux/UserSaga.js index 5b614b1e2ebba172cc9de86aa64f065f908dd0a1..c3a30eb2651d7714329a77d4ef8f669aa5db6358 100644 --- a/src/app/redux/UserSaga.js +++ b/src/app/redux/UserSaga.js @@ -23,6 +23,11 @@ import { import { loadFollows } from 'app/redux/FollowSaga'; import { translate } from 'app/Translator'; import DMCAUserList from 'app/utils/DMCAUserList'; +import { + setHiveSignerAccessToken, + isLoggedInWithHiveSigner, + hiveSignerClient, +} from 'app/utils/HiveSigner'; export const userWatches = [ takeLatest( @@ -129,6 +134,10 @@ function* usernamePasswordLogin2({ username, password, useKeychain, + access_token, + expires_in, + useHiveSigner, + lastPath, saveLogin, operationType /*high security*/, afterLoginRedirectToWelcome, @@ -151,7 +160,8 @@ function* usernamePasswordLogin2({ memoWif, login_owner_pubkey, login_wif_owner_pubkey, - login_with_keychain; + login_with_keychain, + login_with_hivesigner; if (!username && !password) { const data = localStorage.getItem('autopost2'); if (data) { @@ -164,13 +174,25 @@ function* usernamePasswordLogin2({ memoWif, login_owner_pubkey, login_with_keychain, + login_with_hivesigner, + access_token, + expires_in, ] = extractLoginData(data); memoWif = clean(memoWif); login_owner_pubkey = clean(login_owner_pubkey); } } // no saved password - if (!username || !(password || useKeychain || login_with_keychain)) { + if ( + !username || + !( + password || + useKeychain || + login_with_keychain || + useHiveSigner || + login_with_hivesigner + ) + ) { console.log('No saved password'); const offchain_account = yield select(state => state.offchain.get('account') @@ -216,8 +238,26 @@ function* usernamePasswordLogin2({ return; } + // return if already logged in using HiveSigner + if (login_with_hivesigner) { + console.log('Logged in using HiveSigner'); + if (access_token) { + setHiveSignerAccessToken(username, access_token, expires_in); + yield put( + userActions.setUser({ + username, + login_with_hivesigner: true, + access_token, + expires_in, + effective_vests: effectiveVests(account), + }) + ); + } + return; + } + let private_keys; - if (!useKeychain) { + if (!useKeychain && !useHiveSigner) { try { const private_key = PrivateKey.fromWif(password); login_wif_owner_pubkey = private_key.toPublicKey().toString(); @@ -420,6 +460,27 @@ function* usernamePasswordLogin2({ effective_vests: effectiveVests(account), }) ); + } else if (useHiveSigner) { + if (access_token) { + // redirect url + feedURL = '/@' + username + '/feed'; + // set access setHiveSignerAccessToken + setHiveSignerAccessToken( + username, + access_token, + expires_in + ); + // set user data + yield put( + userActions.setUser({ + username, + login_with_hivesigner: true, + access_token, + expires_in, + effective_vests: effectiveVests(account), + }) + ); + } } else { const sign = (role, d) => { console.log('Sign before'); @@ -443,25 +504,30 @@ function* usernamePasswordLogin2({ if (!autopost && saveLogin) yield put(userActions.saveLogin()); // Feature Flags - if (useKeychain || private_keys.get('posting_private')) { + if (useKeychain || useHiveSigner || private_keys.get('posting_private')) { yield fork( getFeatureFlags, username, - useKeychain ? null : private_keys.get('posting_private').toString() + useKeychain || useHiveSigner + ? null + : private_keys.get('posting_private').toString() ); } // TOS acceptance yield fork(promptTosAcceptance, username); // Redirect user to the appropriate page after login. + const path = useHiveSigner ? lastPath : document.location.pathname; if (afterLoginRedirectToWelcome) { console.log('Redirecting to welcome page'); browserHistory.push('/welcome'); - } else if (feedURL && document.location.pathname === '/login.html') { + } else if (feedURL && path === '/login.html') { browserHistory.push('/trending/my'); - } else if (feedURL && document.location.pathname === '/') { + } else if (feedURL && path === '/') { //browserHistory.push(feedURL); browserHistory.push('/trending/my'); + } else if (useHiveSigner && lastPath) { + browserHistory.push(lastPath); } } @@ -523,11 +589,17 @@ function* saveLogin_localStorage() { private_keys, login_owner_pubkey, login_with_keychain, + login_with_hivesigner, + access_token, + expires_in, ] = yield select(state => [ state.user.getIn(['current', 'username']), state.user.getIn(['current', 'private_keys']), state.user.getIn(['current', 'login_owner_pubkey']), state.user.getIn(['current', 'login_with_keychain']), + state.user.getIn(['current', 'login_with_hivesigner']), + state.user.getIn(['current', 'access_token']), + state.user.getIn(['current', 'expires_in']), ]); if (!username) { console.error('Not logged in'); @@ -535,7 +607,7 @@ function* saveLogin_localStorage() { } // Save the lowest security key const posting_private = private_keys && private_keys.get('posting_private'); - if (!login_with_keychain && !posting_private) { + if (!login_with_keychain && !login_with_hivesigner && !posting_private) { console.error('No posting key to save?'); return; } @@ -573,7 +645,10 @@ function* saveLogin_localStorage() { postingPrivateWif, memoWif, login_owner_pubkey, - login_with_keychain + login_with_keychain, + login_with_hivesigner, + access_token, + expires_in ); // autopost is a auto login for a low security key (like the posting key) localStorage.setItem('autopost2', data); @@ -662,12 +737,13 @@ function* uploadImage({ const stateUser = yield select(state => state.user); const username = stateUser.getIn(['current', 'username']); const keychainLogin = isLoggedInWithKeychain(); + const hiveSignerLogin = isLoggedInWithHiveSigner(); const d = stateUser.getIn(['current', 'private_keys', 'posting_private']); if (!username) { progress({ error: 'Please login first.' }); return; } - if (!(keychainLogin || d)) { + if (!(keychainLogin || hiveSignerLogin || d)) { progress({ error: 'Login with your posting key' }); return; } @@ -711,27 +787,35 @@ function* uploadImage({ } let sig; - if (keychainLogin) { - const response = yield new Promise(resolve => { - window.hive_keychain.requestSignBuffer( - username, - JSON.stringify(buf), - 'Posting', - response => { - resolve(response); - } - ); - }); - if (response.success) { - sig = response.result; + let postUrl; + if (hiveSignerLogin) { + // verify user with access_token for HiveSigner login + postUrl = `${$STM_Config.upload_image}/hs/${ + hiveSignerClient.accessToken + }`; + } else { + if (keychainLogin) { + const response = yield new Promise(resolve => { + window.hive_keychain.requestSignBuffer( + username, + JSON.stringify(buf), + 'Posting', + response => { + resolve(response); + } + ); + }); + if (response.success) { + sig = response.result; + } else { + progress({ error: response.message }); + return; + } } else { - progress({ error: response.message }); - return; + sig = Signature.signBufferSha256(bufSha, d).toHex(); } - } else { - sig = Signature.signBufferSha256(bufSha, d).toHex(); + postUrl = `${$STM_Config.upload_image}/${username}/${sig}`; } - const postUrl = `${$STM_Config.upload_image}/${username}/${sig}`; const xhr = new XMLHttpRequest(); xhr.open('POST', postUrl); diff --git a/src/app/utils/HiveSigner.js b/src/app/utils/HiveSigner.js new file mode 100644 index 0000000000000000000000000000000000000000..a7b1f45431f046616d838ca33d6ba05c242e5978 --- /dev/null +++ b/src/app/utils/HiveSigner.js @@ -0,0 +1,61 @@ +import { isLoggedIn, extractLoginData } from 'app/utils/UserUtil'; +import hivesigner from 'hivesigner'; +import { APP_URL, HIVE_SIGNER_APP } from 'app/client_config'; +import { encodeOps } from 'hive-uri'; + +const isBrowser = () => typeof window !== 'undefined' && window; + +const HOST_URL = isBrowser() + ? window.location.protocol + '//' + window.location.host + : APP_URL; + +const HIVE_SIGNER_URL = 'https://hivesigner.com'; + +export const hiveSignerClient = new hivesigner.Client({ + app: HIVE_SIGNER_APP, + callbackURL: `${HOST_URL}/login/hivesigner`, + // scope: ['vote', 'comment'], +}); + +/** + * + * @returns {boolean} + */ +export function isLoggedInWithHiveSigner() { + if (!isLoggedIn()) { + return false; + } + const data = localStorage.getItem('autopost2'); + const [ + username, + password, + memoWif, + login_owner_pubkey, + login_with_keychain, + login_with_hive_signer, + ] = extractLoginData(data); + return !!login_with_hive_signer; +} + +export const setHiveSignerAccessToken = ( + username, + access_token, + expires_in +) => { + // set access token for Hive Signer + console.log(`HiveSigner: set access token for @${username}`); + hiveSignerClient.setAccessToken(access_token); +}; + +export const sendOperationsWithHiveSigner = (ops, params, cb) => { + if (!params) params = {}; + if (!params.callback && isBrowser()) { + params.callback = window.location.href; + } + const uri = encodeOps(ops, params); + const webUrl = uri.replace('hive://', `${HIVE_SIGNER_URL}/`); + if (cb && isBrowser()) { + window.location = webUrl; + } + return webUrl; +}; diff --git a/src/app/utils/Links.js b/src/app/utils/Links.js index 142653f5d7f8420c1a80df994288b0be9647e70d..b6982c96b3908d07d6b82062aeea161acb6edf00 100644 --- a/src/app/utils/Links.js +++ b/src/app/utils/Links.js @@ -98,6 +98,25 @@ export const determineViewMode = search => { return ''; }; +/** + * Returns a new object contains the parameters in a query (window.location.search) + * @param query + * @returns {*} + */ +export const getQueryStringParams = query => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split('&') + .reduce((params, param) => { + let [key, value] = param.split('='); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, ' ')) + : ''; + return params; + }, {}) + : {}; +}; + // Original regex // const urlRegex = '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$'; diff --git a/src/app/utils/UserUtil.js b/src/app/utils/UserUtil.js index 7827cdb6a626c0a6eca19829359f6a5942e6aaa4..21aa1e8a3105c7771eee99e807e273c5891f1a00 100644 --- a/src/app/utils/UserUtil.js +++ b/src/app/utils/UserUtil.js @@ -14,16 +14,21 @@ export const packLoginData = ( password, memoWif, login_owner_pubkey, - login_with_keychain + login_with_keychain, + login_with_hive_signer, + access_token, + expires_in ) => new Buffer( `${username}\t${password}\t${memoWif || ''}\t${login_owner_pubkey || - ''}\t${login_with_keychain || ''}` + ''}\t${login_with_keychain || ''}\t${login_with_hive_signer || + ''}\t${access_token || ''}\t${expires_in || ''}` ).toString('hex'); /** * - * @returns {array} [username, password, memoWif, login_owner_pubkey, login_with_keychain] + * @returns {array} [username, password, memoWif, login_owner_pubkey, login_with_keychain, + * login_with_hive_signer] */ export const extractLoginData = data => new Buffer(data, 'hex').toString().split('\t'); diff --git a/yarn.lock b/yarn.lock index 08b7d21025275ecffe70aeee2f55727e7fceb8b6..44b70cff331c3a1e1ce7d3f31a3089f4aa2bab4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2708,6 +2708,13 @@ cross-fetch@^1.1.1: node-fetch "1.7.3" whatwg-fetch "2.0.3" +cross-fetch@^3.0.1: + version "3.0.5" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.5.tgz#2739d2981892e7ab488a7ad03b92df2816e03f4c" + integrity sha512-FFLcLtraisj5eteosnX1gf01qYDCOc4fDy0+euOt8Kn9YBY2NtXL/pCoYPavw24NIQkQqm5ZOLsGD5Zzj0gyew== + dependencies: + node-fetch "2.6.0" + cross-spawn@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" @@ -4489,6 +4496,20 @@ history@^3.0.0: query-string "^4.2.2" warning "^3.0.0" +hive-uri@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/hive-uri/-/hive-uri-0.2.2.tgz#60d57a77a2c7a6394471f700e436f3f9822c737d" + integrity sha512-95XH50GsJ+ZuWsLQaNcqYiZ6lmoVDawjG+BCgERqOkoy57b+OgHeNDPeYYY9qkNIi0ThcaYRi6RHVcLbI5EfBw== + +hivesigner@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/hivesigner/-/hivesigner-3.2.0.tgz#25f4e450716c53d2b16fd0edf085609e679c6ba0" + integrity sha512-yeEnTAL1gQjkHPLEY5Rt8GQB2pC2qi9fdFY3W8tDPFZjQgRW82SU9f08lf2xF6YJ7thAl/9yM24N9/78SK7vZw== + dependencies: + babel-runtime "^6.26.0" + cross-fetch "^3.0.1" + hive-uri "^0.2.2" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -6533,6 +6554,11 @@ node-fetch@1.7.3, node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-fetch@2.6.0: + version "2.6.0" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"