diff --git a/js/package.json b/js/package.json
index 12b0cd9c6a0..d798f9225d0 100644
--- a/js/package.json
+++ b/js/package.json
@@ -128,6 +128,7 @@
"es6-error": "^4.0.0",
"es6-promise": "^3.2.1",
"ethereumjs-tx": "^1.1.2",
+ "eventemitter3": "^2.0.2",
"file-saver": "^1.3.3",
"format-json": "^1.0.3",
"format-number": "^2.0.1",
diff --git a/js/src/3rdparty/sms-verification/index.js b/js/src/3rdparty/sms-verification/index.js
index 9b113f36433..c50b2331a80 100644
--- a/js/src/3rdparty/sms-verification/index.js
+++ b/js/src/3rdparty/sms-verification/index.js
@@ -27,9 +27,10 @@ export const termsOfService = (
);
-export const postToServer = (query) => {
+export const postToServer = (query, isTestnet = false) => {
+ const port = isTestnet ? 8443 : 443;
query = stringify(query);
- return fetch('https://sms-verification.parity.io/?' + query, {
+ return fetch(`https://sms-verification.parity.io:${port}/?` + query, {
method: 'POST', mode: 'cors', cache: 'no-store'
})
.then((res) => {
diff --git a/js/src/contracts/abi/sms-verification.json b/js/src/contracts/abi/sms-verification.json
index 400d22b4477..d6852b18234 100644
--- a/js/src/contracts/abi/sms-verification.json
+++ b/js/src/contracts/abi/sms-verification.json
@@ -1 +1 @@
-[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
+[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"request","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"},{"name":"_puzzle","type":"bytes32"}],"name":"puzzle","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_code","type":"bytes32"}],"name":"confirm","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Requested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"},{"indexed":false,"name":"puzzle","type":"bytes32"}],"name":"Puzzled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
diff --git a/js/src/contracts/sms-verification.js b/js/src/contracts/sms-verification.js
index 2d32556ea21..34a6bad7620 100644
--- a/js/src/contracts/sms-verification.js
+++ b/js/src/contracts/sms-verification.js
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see
Requesting an SMS from the Parity server and waiting for the puzzle to be put into the contract.
); default: diff --git a/js/src/modals/SMSVerification/store.js b/js/src/modals/SMSVerification/store.js index 8c4db373a52..76045d814ab 100644 --- a/js/src/modals/SMSVerification/store.js +++ b/js/src/modals/SMSVerification/store.js @@ -20,19 +20,16 @@ import { sha3 } from '../../api/util/sha3'; import Contracts from '../../contracts'; -import { checkIfVerified, checkIfRequested } from '../../contracts/sms-verification'; +import { checkIfVerified, checkIfRequested, awaitPuzzle } from '../../contracts/sms-verification'; import { postToServer } from '../../3rdparty/sms-verification'; import checkIfTxFailed from '../../util/check-if-tx-failed'; import waitForConfirmations from '../../util/wait-for-block-confirmations'; -const validCode = /^[A-Z\s]+$/i; - export const LOADING = 'fetching-contract'; export const QUERY_DATA = 'query-data'; export const POSTING_REQUEST = 'posting-request'; export const POSTED_REQUEST = 'posted-request'; export const REQUESTING_SMS = 'requesting-sms'; -export const REQUESTED_SMS = 'requested-sms'; export const QUERY_CODE = 'query-code'; export const POSTING_CONFIRMATION = 'posting-confirmation'; export const POSTED_CONFIRMATION = 'posted-confirmation'; @@ -50,11 +47,9 @@ export default class VerificationStore { @observable number = ''; @observable requestTx = null; @observable code = ''; + @observable isCodeValid = null; @observable confirmationTx = null; - @computed get isCodeValid () { - return validCode.test(this.code); - } @computed get isNumberValid () { return phone.isValidNumber(this.number); } @@ -72,20 +67,19 @@ export default class VerificationStore { return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null; case QUERY_DATA: return this.isNumberValid && this.consentGiven; - case REQUESTED_SMS: - return this.requestTx; case QUERY_CODE: - return this.isCodeValid; + return this.requestTx && this.isCodeValid === true; case POSTED_CONFIRMATION: - return this.confirmationTx; + return !!this.confirmationTx; default: return false; } } - constructor (api, account) { + constructor (api, account, isTestnet) { this.api = api; this.account = account; + this.isTestnet = isTestnet; this.step = LOADING; Contracts.create(api).registry.getContract('smsverification') @@ -151,7 +145,26 @@ export default class VerificationStore { } @action setCode = (code) => { + const { contract, account } = this; + if (!contract || !account || code.length === 0) return; + + const confirm = contract.functions.find((fn) => fn.name === 'confirm'); + const options = { from: account }; + const values = [ sha3(code) ]; + this.code = code; + this.isCodeValid = null; + confirm.estimateGas(options, values) + .then((gas) => { + options.gas = gas.mul(1.2).toFixed(0); + return confirm.call(options, values); + }) + .then((result) => { + this.isCodeValid = result === true; + }) + .catch((err) => { + this.error = 'Failed to check if the code is valid: ' + err.message; + }); } @action sendRequest = () => { @@ -188,11 +201,15 @@ export default class VerificationStore { chain .then(() => { + return api.parity.netChain(); + }) + .then((chain) => { this.step = REQUESTING_SMS; - return postToServer({ number, address: account }); + return postToServer({ number, address: account }, this.isTestnet); }) + .then(() => awaitPuzzle(api, contract, account)) .then(() => { - this.step = REQUESTED_SMS; + this.step = QUERY_CODE; }) .catch((err) => { this.error = 'Failed to request a confirmation SMS: ' + err.message; diff --git a/js/src/util/is-testnet.js b/js/src/util/is-testnet.js new file mode 100644 index 00000000000..c2bf2c45049 --- /dev/null +++ b/js/src/util/is-testnet.js @@ -0,0 +1,19 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see