diff --git a/api/rest/wallet.go b/api/rest/wallet.go index a5949c3..4bb6d08 100644 --- a/api/rest/wallet.go +++ b/api/rest/wallet.go @@ -265,36 +265,43 @@ func (w *WebBridgeRunner) postmnemonic(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": strErrMsg}) return } - cmd := `dynamic-cli importmnemonic "` + req.Mnemonic + `"` - if len(req.Language) > 0 { - cmd += ` "` + req.Language + `"` - } else { - cmd += ` "english"` - } - if len(req.Passphrase) > 0 { - cmd += ` "` + req.Passphrase + `"` - } - strCommand, _ := dynamic.NewRequest(cmd) - response, _ := <-w.dynamicd.ExecCmdRequest(strCommand) - if strings.Contains(response, "Error:") { - result := models.RPCError{} - err := json.Unmarshal([]byte(response), &result) + wordCount := len(strings.Split(req.Mnemonic, " ")) + if wordCount == 12 || wordCount == 13 || wordCount == 24 || wordCount == 25 { + cmd := `dynamic-cli importmnemonic "` + req.Mnemonic + `"` + if len(req.Language) > 0 { + cmd += ` "` + req.Language + `"` + } else { + cmd += ` "english"` + } + if len(req.Passphrase) > 0 { + cmd += ` "` + req.Passphrase + `"` + } + strCommand, _ := dynamic.NewRequest(cmd) + response, _ := <-w.dynamicd.ExecCmdRequest(strCommand) + if strings.Contains(response, "Error:") { + result := models.RPCError{} + err := json.Unmarshal([]byte(response), &result) + if err != nil { + strErrMsg := fmt.Sprintf("Response JSON unmarshal error %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": strErrMsg}) + return + } + c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error}) + return + } + var result interface{} + err = json.Unmarshal([]byte(response), &result) if err != nil { - strErrMsg := fmt.Sprintf("Response JSON unmarshal error %v", err) + strErrMsg := fmt.Sprintf("Results JSON unmarshal error %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": strErrMsg}) return } - c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error}) - return - } - var result interface{} - err = json.Unmarshal([]byte(response), &result) - if err != nil { - strErrMsg := fmt.Sprintf("Results JSON unmarshal error %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": strErrMsg}) + c.JSON(http.StatusOK, gin.H{"result": result}) + } else { + strErrMsg := fmt.Sprintf("Incorrect number of words (%v) in mnemonic", wordCount) + c.JSON(http.StatusBadRequest, gin.H{"error": strErrMsg}) return } - c.JSON(http.StatusOK, gin.H{"result": result}) } // diff --git a/web/package-lock.json b/web/package-lock.json index c4fb889..17df696 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1410,6 +1410,71 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@redux-saga/core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz", + "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==", + "requires": { + "@babel/runtime": "^7.6.3", + "@redux-saga/deferred": "^1.1.2", + "@redux-saga/delay-p": "^1.1.2", + "@redux-saga/is": "^1.1.2", + "@redux-saga/symbols": "^1.1.2", + "@redux-saga/types": "^1.1.0", + "redux": "^4.0.4", + "typescript-tuple": "^2.2.1" + } + }, + "@redux-saga/deferred": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz", + "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ==" + }, + "@redux-saga/delay-p": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz", + "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==", + "requires": { + "@redux-saga/symbols": "^1.1.2" + } + }, + "@redux-saga/is": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz", + "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==", + "requires": { + "@redux-saga/symbols": "^1.1.2", + "@redux-saga/types": "^1.1.0" + } + }, + "@redux-saga/symbols": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz", + "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ==" + }, + "@redux-saga/types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz", + "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg==" + }, + "@reduxjs/toolkit": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.4.0.tgz", + "integrity": "sha512-hkxQwVx4BNVRsYdxjNF6cAseRmtrkpSlcgJRr3kLUcHPIAMZAmMJkXmHh/eUEGTMqPzsYpJLM7NN2w9fxQDuGw==", + "requires": { + "immer": "^7.0.3", + "redux": "^4.0.0", + "redux-thunk": "^2.3.0", + "reselect": "^4.0.0" + }, + "dependencies": { + "immer": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/immer/-/immer-7.0.9.tgz", + "integrity": "sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==" + } + } + }, "@semantic-ui-react/event-stack": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.1.tgz", @@ -1715,6 +1780,30 @@ "@types/node": "*" } }, + "@types/history": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.8.tgz", + "integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==" + }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + } + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -1792,6 +1881,36 @@ "@types/react": "*" } }, + "@types/react-redux": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.9.tgz", + "integrity": "sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + } + } + }, + "@types/react-router": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz", + "integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==", + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, "@types/sjcl": { "version": "1.0.29", "resolved": "https://registry.npmjs.org/@types/sjcl/-/sjcl-1.0.29.tgz", @@ -3840,6 +3959,14 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" }, + "connected-react-router": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.8.0.tgz", + "integrity": "sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg==", + "requires": { + "prop-types": "^15.7.2" + } + }, "console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -6443,6 +6570,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -7180,7 +7320,6 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "^2.6.1", "whatwg-fetch": ">=0.10.0" }, "dependencies": { @@ -8404,6 +8543,15 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" }, + "mini-create-react-context": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz", + "integrity": "sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==", + "requires": { + "@babel/runtime": "^7.5.5", + "tiny-warning": "^1.0.3" + } + }, "mini-css-extract-plugin": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", @@ -10900,6 +11048,68 @@ "warning": "^4.0.2" } }, + "react-redux": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz", + "integrity": "sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==", + "requires": { + "@babel/runtime": "^7.5.5", + "hoist-non-react-statics": "^3.3.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.9.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + } + } + }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, "react-scripts": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.3.tgz", @@ -11022,6 +11232,49 @@ "strip-indent": "^3.0.0" } }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-injectors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/redux-injectors/-/redux-injectors-1.3.0.tgz", + "integrity": "sha512-ZoyKf8Y0bRqpmJImaVO3jnDKuMXTzMDp3j+b0bqtSuPAgWcHD/2P9gRr4mI1EjgCiheIyQ/JJI8yLG29ijqRaw==", + "requires": { + "hoist-non-react-statics": "^3.3.2", + "invariant": "^2.2.4", + "lodash": "^4.17.15", + "redux": "^4.0.5" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + } + } + }, + "redux-saga": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz", + "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==", + "requires": { + "@redux-saga/core": "^1.1.3" + } + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, "regenerate": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", @@ -11261,6 +11514,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, "resolve": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", @@ -11282,6 +11540,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -12631,6 +12894,11 @@ "util.promisify": "~1.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -12899,6 +13167,16 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13045,11 +13323,37 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typesafe-actions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/typesafe-actions/-/typesafe-actions-5.1.0.tgz", + "integrity": "sha512-bna6Yi1pRznoo6Bz1cE6btB/Yy8Xywytyfrzu/wc+NFW3ZF0I+2iCGImhBsoYYCOWuICtRO4yHcnDlzgo1AdNg==" + }, "typescript": { "version": "3.7.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==" }, + "typescript-compare": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", + "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==", + "requires": { + "typescript-logic": "^0.0.0" + } + }, + "typescript-logic": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", + "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==" + }, + "typescript-tuple": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz", + "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==", + "requires": { + "typescript-compare": "^0.0.2" + } + }, "ua-parser-js": { "version": "0.7.22", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz", @@ -13305,6 +13609,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/web/package.json b/web/package.json index eb5b140..bc0b8b7 100644 --- a/web/package.json +++ b/web/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@reduxjs/toolkit": "^1.4.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", @@ -10,18 +11,27 @@ "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", + "@types/react-redux": "^7.1.9", + "@types/react-router": "^5.1.8", "@types/sjcl": "^1.0.29", "axios": "^0.20.0", + "connected-react-router": "^6.8.0", "node-fetch": "^2.6.1", "node-forge": "0.10.0", "qrcode-generator": "^1.4.4", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-redux": "^7.2.1", + "react-router": "^5.2.0", "react-scripts": "3.4.3", + "redux": "^4.0.5", + "redux-injectors": "^1.3.0", + "redux-saga": "^1.1.3", "semantic-ui-css": "^2.4.1", "semantic-ui-react": "^1.3.0", "sjcl": "^1.0.8", "terminal-in-react": "^4.3.1", + "typesafe-actions": "^5.1.0", "typescript": "~3.7.2", "yarn": "^1.22.5" }, diff --git a/web/src/api/Wallet.ts b/web/src/api/Wallet.ts index ccb5c5e..cf75d64 100644 --- a/web/src/api/Wallet.ts +++ b/web/src/api/Wallet.ts @@ -49,14 +49,27 @@ export const GetWalletAddresses = async (): Promise => { } export const RestoreMnemonic = async (mnemonic: ImportMnemonicRequest): Promise => { - return await axios.post("/wallet/mnemonic", mnemonic, RequestConfig).then(function (response) { - return response.data; - }).catch(function (error) { - var errMessage = "RestoreMnemonic execute [Post] /wallet/mnemonic error: " + error; - console.log(errMessage); - var errResponse: ImportMnemonicResponse = { - done: "failed" - } - return errResponse; - }); + const wordCount = mnemonic.mnemonic.split(" ").length; + if ( + wordCount === 12 || + wordCount === 13 || + wordCount === 24 || + wordCount === 25 + ) { + return await axios.post("/wallet/mnemonic", mnemonic, RequestConfig).then(function (response) { + return response.data; + }).catch(function (error) { + var errMessage = "RestoreMnemonic execute [Post] /wallet/mnemonic error: " + error; + console.log(errMessage); + var errResponse: ImportMnemonicResponse = { + done: "failed" + } + return errResponse; + }); + } else { + var response: ImportMnemonicResponse = { + done: "Word count error" + }; + return response; + } } \ No newline at end of file diff --git a/web/src/components/SetupWizard.tsx b/web/src/components/SetupWizard.tsx index d0a08b7..b0b3466 100644 --- a/web/src/components/SetupWizard.tsx +++ b/web/src/components/SetupWizard.tsx @@ -9,6 +9,7 @@ export interface SetupWizardProps { export interface SetupWizardState { currentStep?: number; + mnemonic?: string; } export class SetupWizard extends Component { @@ -76,7 +77,12 @@ export class SetupWizard extends Component { {this.state && this.state.currentStep === 1 && ( - this.props.onComplete()} /> + this.props.onComplete()} + onCancel={() => this.setState({ currentStep: 1 })} + walletImportMnemonic={(mnemonic) => this.setState({ mnemonic: mnemonic })} + complete={false} + /> )} diff --git a/web/src/components/ui/Button.tsx b/web/src/components/ui/Button.tsx index c0d5617..179d6df 100644 --- a/web/src/components/ui/Button.tsx +++ b/web/src/components/ui/Button.tsx @@ -73,6 +73,22 @@ const ArrowButton: React.FunctionComponent = ({ ); +const StyledBackArrowButton = styled("div")` + display: block; + direction: column; + width: 100px; + cursor: pointer; +`; + +const BackArrowButton: React.FunctionComponent<{ + onClick: () => void; + marginTop?: string; +}> = ({ onClick, marginTop }) => ( + onClick()}> + + +); + const LightButton = styled("button")` align-self: ${(props) => (props.align ? props.align : "center")}; justify-content: center; @@ -91,4 +107,4 @@ const LightButton = styled("button")` export default StyledButton; -export { ArrowButton, BackButton, LightButton }; +export { ArrowButton, BackArrowButton, BackButton, LightButton }; diff --git a/web/src/components/wallet/FileRestore.tsx b/web/src/components/wallet/FileRestore.tsx index e867d9f..844151b 100644 --- a/web/src/components/wallet/FileRestore.tsx +++ b/web/src/components/wallet/FileRestore.tsx @@ -10,12 +10,12 @@ import { H3, Text } from "../ui/Text"; import { FilePathInfo } from "../../shared/FilePathInfo"; import { WalletRestoreFilePassword } from "./RestoreFilePassword"; import { RequestConfig } from "../../api/Config"; -import { ImportMnemonicRequest } from "../../shared/Mnemonic"; import axios from "axios"; export interface WalletFileRestoreProps { onComplete: () => void; onCancel: () => void; + onRestoreMnemonic: (words: string) => void; } export interface WalletFileRestoreState { @@ -41,7 +41,7 @@ export class WalletFileRestore extends Component< this.waitForRescan = this.waitForRescan.bind(this); this.state = { loading: false - } + }; } componentDidMount(): void { @@ -64,7 +64,7 @@ export class WalletFileRestore extends Component< private onMnemonic = async (wordlist: string) => { var self = this; - console.log('onMnemonic'); + console.log("onMnemonic"); const wordCount = wordlist.split(" ").length; if ( wordCount === 12 || @@ -72,15 +72,8 @@ export class WalletFileRestore extends Component< wordCount === 24 || wordCount === 25 ) { - var request: ImportMnemonicRequest = { - mnemonic: wordlist - } - axios.post("/wallet/mnemonic", request, RequestConfig).then(function (response) { - console.log(JSON.stringify(response.data, null, 2)); - self.setState( { loading: true, mnemonic: wordlist }, self.waitForRescan()); - }).catch(function (error) { - console.log("onMnemonic execute wallet/mnemonic [Post] Error: " + error); - }); + self.props.onRestoreMnemonic(wordlist); + this.setState({ loading: true }); } else { var err: DropzoneError = { title: "Incorrect Word Count", @@ -91,29 +84,27 @@ export class WalletFileRestore extends Component< } }; - // Returns a Promise that resolves after "ms" Milliseconds - private timer(ms: number) { - return new Promise(res => setTimeout(res, ms)); - } - - private waitForRescan(): | undefined { + private waitForRescan(): undefined { //TODO: Use redux-saga for these types of actions - console.log('waitForRescan'); + console.log("waitForRescan"); var self = this; while (this.state.loading) { - console.log('waitForRescan loop before sleep'); - setTimeout(() => - { - console.log('waitForRescan loop after sleep'); - axios.get("/wallet/defaultaddress", RequestConfig) + console.log("waitForRescan loop before sleep"); + setTimeout(() => { + console.log("waitForRescan loop after sleep"); + axios + .get("/wallet/defaultaddress", RequestConfig) .then(function (response) { - console.log('waitForRescan response', response); - self.setState( { loading: false } ); + console.log("waitForRescan response", response); + self.setState({ loading: false }); self.props.onComplete(); - }) - .catch(function (error) { - console.log("waitForRescan execute wallet/defaultaddress [Get] Error: " + error); - }); + }) + .catch(function (error) { + console.log( + "waitForRescan execute wallet/defaultaddress [Get] Error: " + + error + ); + }); }, 5000); } return; @@ -161,6 +152,7 @@ export class WalletFileRestore extends Component< onClick={() => this.props.onCancel()} margin="150px 0 0 -80px" /> + - - - + -

- Restore using Secure Restore File{" "} -

+ +

+ Restore using Secure Restore File +

+
void; onComplete: () => void; + onBackupSecureFile: (mnemonic: string) => void; } export interface MnemonicBackupState { @@ -26,7 +27,7 @@ export class MnemonicBackup extends Component< // bind events this.componentDidMount = this.componentDidMount.bind(this); this.componentDidUnmount = this.componentDidUnmount.bind(this); - this.handleFileCreation = this.handleFileCreation.bind(this); + this.backupSecureFile = this.backupSecureFile.bind(this); this.getMnemonic = this.getMnemonic.bind(this); } @@ -36,9 +37,10 @@ export class MnemonicBackup extends Component< componentDidUnmount(): void {} - handleFileCreation = (e: FormEvent) => { - //if we don't prevent form submission, causes a browser reload - e.preventDefault(); + backupSecureFile = async () => { + if (this.state && this.state.mnemonic) { + this.props.onBackupSecureFile(this.state.mnemonic); + } }; private getMnemonic = async () => { @@ -118,7 +120,7 @@ export class MnemonicBackup extends Component<
- + Create a secure file diff --git a/web/src/components/wallet/SecureFilePassword.tsx b/web/src/components/wallet/SecureFilePassword.tsx new file mode 100644 index 0000000..ccb520f --- /dev/null +++ b/web/src/components/wallet/SecureFilePassword.tsx @@ -0,0 +1,148 @@ +import React, { Component } from "react"; +import { Box } from "../ui/Box"; +import { ArrowButton, BackArrowButton } from "../ui/Button"; +import { Card } from "../ui/Card"; +import { Container } from "../ui/Container"; +import { Input } from "../ui/Input"; +import { SecureFileIcon } from "../ui/Images"; +import { H3, Text } from "../ui/Text"; +import { getAesEncryptor } from "../../shared/AesEncryption"; +import { ValidationResult } from "../../shared/ValidationResult"; + +export interface WalletSecureFilePasswordProps { + mnemonic: string; + onCancel: () => void; + validationResult?: ValidationResult; +} + +export interface WalletSecureFilePasswordState { + password: string; + confirmPassword: string; + error?: string; + fileCipherText?: string; +} + +export class WalletSecureFilePassword extends Component< + WalletSecureFilePasswordProps, + WalletSecureFilePasswordState +> { + constructor(props: WalletSecureFilePasswordProps) { + super(props); + // bind events + this.componentDidMount = this.componentDidMount.bind(this); + this.componentDidUnmount = this.componentDidUnmount.bind(this); + this.encryptSecureMnemonicFile = this.encryptSecureMnemonicFile.bind(this); + + this.state = { password: "", confirmPassword: "" }; + } + + componentDidMount(): void {} + + componentDidUnmount(): void {} + + private encryptSecureMnemonicFile(): void { + if (this.state.password !== this.state.confirmPassword) { + this.setState({ error: "Passwords do not match" }); + return; + } else if (!/.{6,}/.test(this.state.password)) { + this.setState({ error: "Password must be > 6 characters" }); + return; + } + if (this.state.password) { + try { + const { encrypt } = getAesEncryptor(this.state.password); + const encryptedMnemonic = "data:application/json;base64," + encrypt(this.props.mnemonic); + console.log(encryptedMnemonic); + this.setState({ fileCipherText: encryptedMnemonic }); + } catch (e) { + console.log("Error:", e); + } + } + } + + render() { + const { onCancel } = this.props; + const { error } = this.state; + return ( + <> + + + +
+ onCancel()} /> + + + + + + +

Secure file

+ + Create a secure file password{" "} + + + this.setState({ password: e.target.value }) + } + placeholder="Password" + type="password" + margin="1em 0 1em 0" + padding="0 1em 0 1em" + autoFocus={true} + error={error ? true : false} + /> + Confirm Password + + this.setState({ confirmPassword: e.target.value }) + } + placeholder="Password" + type="password" + margin="1em 0 1em 0" + padding="0 1em 0 1em" + error={error ? true : false} + /> + {this.state && this.state.error ? ( + + {this.state.error} + + ) : ( + <> + )} +
+
+
+
+
+ + this.encryptSecureMnemonicFile()} + /> + +
+
+ + ); + } +} diff --git a/web/src/components/wallet/Setup.tsx b/web/src/components/wallet/Setup.tsx index 3303f8b..0631dc2 100644 --- a/web/src/components/wallet/Setup.tsx +++ b/web/src/components/wallet/Setup.tsx @@ -10,6 +10,9 @@ import { WalletRestore } from "./Restore"; import { WalletFileRestore } from "./FileRestore"; import { WalletMnemonicRestore } from "./MnemonicRestore"; import { WalletPassword } from "./WalletPassword"; +import { PickedDispatchProps } from "../../state/shared/PickedDispatchProps"; +import { ManageWalletActions } from "../../state/actions/manageWallet"; +import { WalletSecureFilePassword } from "./SecureFilePassword"; enum SetupState { Init = 1, @@ -18,36 +21,57 @@ enum SetupState { Restore, RestoreWithMnemonic, RestoreWithSecureFile, - CreatePassword + BackupSecureFile, + CreatePassword, + Waiting, + Complete, } export interface WalletSetupProps { onComplete: () => void; + onCancel: () => void; + complete: boolean; } +export type WalletViewDispatch = PickedDispatchProps; + +type WalletViewDispatchProps = WalletSetupProps & WalletViewDispatch; + export interface WalletSetupState { setupState: SetupState; + mnemonic?: string; } -export class WalletSetup extends Component { - constructor(props: WalletSetupProps) { +export class WalletSetup extends Component { + constructor(props: WalletViewDispatchProps) { super(props); // bind events this.componentDidMount = this.componentDidMount.bind(this); this.componentDidUnmount = this.componentDidUnmount.bind(this); - this.onNewWallet = this.onNewWallet.bind(this); + this.onInitWallet = this.onInitWallet.bind(this); + this.onRequestNewWallet = this.onRequestNewWallet.bind(this); + this.onRequestRestoreWallet = this.onRequestRestoreWallet.bind(this); } componentDidMount(): void { this.setState({ setupState: SetupState.Init }); + this.onInitWallet(); } componentDidUnmount(): void {} - private onNewWallet(): void { - this.props.onComplete(); + private onInitWallet(): void { + this.props.walletImportMnemonic("hello test green oil elephant"); + } + + private onRequestNewWallet(): void { + this.setState({ setupState: SetupState.New }) + } + + private onRequestRestoreWallet(): void { + this.setState({ setupState: SetupState.Restore }) } render() { @@ -63,7 +87,7 @@ export class WalletSetup extends Component { this.setState({ setupState: SetupState.New })} + onClick={() => this.onRequestNewWallet()} >

@@ -74,10 +98,7 @@ export class WalletSetup extends Component { - this.setState({ setupState: SetupState.Restore }) - } - > + onClick={() =>this.onRequestRestoreWallet()}>

Restore Wallet @@ -105,13 +126,29 @@ export class WalletSetup extends Component { onComplete={() => this.setState({ setupState: SetupState.CreatePassword }) } + onBackupSecureFile={(mnemonic) => this.setState({ setupState: SetupState.BackupSecureFile, mnemonic: mnemonic })} /> )} + {this.state && + this.state.setupState === SetupState.BackupSecureFile && this.state.mnemonic && ( + this.setState({ setupState: SetupState.NewWarned })} + /> + )} + {this.state && + this.state.setupState === SetupState.RestoreWithSecureFile && ( + this.props.onComplete()} + onCancel={() => this.setState({ setupState: SetupState.Restore })} + onRestoreMnemonic={(words) => this.props.walletImportMnemonic(words)} + /> + )} {this.state && this.state.setupState === SetupState.CreatePassword && ( this.props.onComplete()} uiType={"CREATE"} - onCancel={() => this.setState({ setupState: SetupState.Init })} + onCancel={() => this.setState({ setupState: SetupState.NewWarned })} /> )} {this.state && this.state.setupState === SetupState.Restore && ( @@ -131,14 +168,7 @@ export class WalletSetup extends Component { onComplete={() => this.props.onComplete()} onCancel={() => this.setState({ setupState: SetupState.Restore })} /> - )} - {this.state && - this.state.setupState === SetupState.RestoreWithSecureFile && ( - this.props.onComplete()} - onCancel={() => this.setState({ setupState: SetupState.Restore })} - /> - )} + )} ); } diff --git a/web/src/index.tsx b/web/src/index.tsx index 7f42063..d218aeb 100644 --- a/web/src/index.tsx +++ b/web/src/index.tsx @@ -1,20 +1,28 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; +import { Provider } from "react-redux"; import * as serviceWorker from './serviceWorker'; +import App from './App'; import 'semantic-ui-css/semantic.min.css' +import './index.css'; +import configureStore from "./state/store"; import { RestBaseUrl } from './api/Config'; import axios from 'axios'; // set default baseURL axios.defaults.baseURL = RestBaseUrl; +// setup redux store +const initialState = {}; +const store = configureStore(initialState); + ReactDOM.render( - + + + , - document.getElementById('root') + document.getElementById("root") ); // If you want your app to work offline and load faster, you can change diff --git a/web/src/shared/ValidationResult.ts b/web/src/shared/ValidationResult.ts new file mode 100644 index 0000000..c23535f --- /dev/null +++ b/web/src/shared/ValidationResult.ts @@ -0,0 +1,28 @@ +export interface ValidationResult { + value: T; + success: boolean; + validationMessages: string[]; + isError: boolean +} + +interface NameIndictator { + name: string; + scope: string; +} + +export interface NameIndicatorWithValue extends NameIndictator { + value: T; +} + +export type NamedValue = T extends void ? NameIndictator : NameIndicatorWithValue; + +export const createValidatedFailurePayload = (fieldScope: string, fieldName: string, message: string, fieldValue: T, isError = false): NamedValue> => ({ + scope: fieldScope, + name: fieldName, + value: { + success: false, + validationMessages: [message], + value: fieldValue, + isError: isError + } +}) diff --git a/web/src/state/actions/index.ts b/web/src/state/actions/index.ts new file mode 100644 index 0000000..7773d9a --- /dev/null +++ b/web/src/state/actions/index.ts @@ -0,0 +1,8 @@ +import { ActionType } from "typesafe-actions"; +import { ManageWalletActions } from "./manageWallet"; + +export const RootActions = { + ...ManageWalletActions +}; + +export type RootActions = ActionType; diff --git a/web/src/state/actions/manageWallet.ts b/web/src/state/actions/manageWallet.ts new file mode 100644 index 0000000..a22d85b --- /dev/null +++ b/web/src/state/actions/manageWallet.ts @@ -0,0 +1,23 @@ +import { ActionType, createAction } from "typesafe-actions"; + +export enum ManageWalletTypes { + INIT = "@@wallet/INIT", + IMPORT_MNEMONIC = "@@wallet/IMPORT_MNEMONIC", + ENCRYPT = "@@wallet/ENCRYPT", + ADD_USER = "@@wallet/ADD_USER", + ADD_LINK = "@@wallet/ADD_LINK", + COMPLETE = "@@wallet/COMPLETE", + CANCEL_RESTORE = "@@wallet/CANCEL_RESTORE", +} + +export const ManageWalletActions = { + walletInit: createAction(ManageWalletTypes.INIT)(), + walletImportMnemonic: createAction(ManageWalletTypes.IMPORT_MNEMONIC)(), + walletEncrypt: createAction(ManageWalletTypes.ENCRYPT)(), + walletAddUser: createAction(ManageWalletTypes.ADD_LINK)(), + walletAddLink: createAction(ManageWalletTypes.ADD_LINK)(), + walletComplete: createAction(ManageWalletTypes.COMPLETE)(), + walletRestoreCancel: createAction(ManageWalletTypes.CANCEL_RESTORE)(), +}; + +export type ManageWalletActions = ActionType; diff --git a/web/src/state/reducers/index.ts b/web/src/state/reducers/index.ts new file mode 100644 index 0000000..dfb2e1f --- /dev/null +++ b/web/src/state/reducers/index.ts @@ -0,0 +1,17 @@ +import { combineReducers } from "redux"; +import { manageWallet } from "./manageWallet"; + +export let rootReducer = combineReducers({ + ...manageWallet +}); + +export default function createReducer(injectedReducers = {}) { + rootReducer = combineReducers({ + ...manageWallet, + ...injectedReducers + }); + + return rootReducer; +} + +export type RootState = ReturnType; diff --git a/web/src/state/reducers/manageWallet.ts b/web/src/state/reducers/manageWallet.ts new file mode 100644 index 0000000..58c8076 --- /dev/null +++ b/web/src/state/reducers/manageWallet.ts @@ -0,0 +1,32 @@ +import { ManageWalletActions } from "../actions/manageWallet"; +import { getType } from "typesafe-actions"; + +export interface ManageWalletState { + complete: boolean; +} + +const defaultState: ManageWalletState = { + complete: false +}; + +export const manageWallet = ( + state: ManageWalletState = defaultState, + action: ManageWalletActions +): ManageWalletState => { + switch (action.type) { + case getType(ManageWalletActions.walletInit): + return { ...state, complete: true }; + case getType(ManageWalletActions.walletImportMnemonic): + return { ...state, complete: true }; + case getType(ManageWalletActions.walletEncrypt): + return { ...state, complete: true }; + case getType(ManageWalletActions.walletAddUser): + return { ...state, complete: true }; + case getType(ManageWalletActions.walletAddLink): + return { ...state, complete: true }; + case getType(ManageWalletActions.walletComplete): + return { ...state, complete: true }; + default: + return state; + } +}; diff --git a/web/src/state/routes/index.ts b/web/src/state/routes/index.ts new file mode 100644 index 0000000..6801e6f --- /dev/null +++ b/web/src/state/routes/index.ts @@ -0,0 +1,30 @@ +import React from "react"; +import { push } from "connected-react-router"; +import { RouteComponentProps } from "react-router"; +import mananageWallet from "../store/manageWallet"; + +export interface RouteInfo { + path: string; + component: + | React.ComponentType> + | React.ComponentType; + exact: boolean; +} + +const route = ( + path: string, + component: + | React.ComponentType> + | React.ComponentType, + exact: boolean = true +): RouteInfo => ({ path, component, exact }); + +const routingTable = { + mananageWallet: route("/mananageWallet", mananageWallet) +}; + +export const pushRoute = (route: RouteInfo) => push(route.path); + +//deepFreeze(routingTable) + +export const appRoutes = routingTable; diff --git a/web/src/state/sagas/index.ts b/web/src/state/sagas/index.ts new file mode 100644 index 0000000..8ca3c63 --- /dev/null +++ b/web/src/state/sagas/index.ts @@ -0,0 +1,12 @@ +import { all, call } from "redux-saga/effects"; +import { watchWalletStatusSaga } from "./manageWallet"; + +export const getRootSaga = () => { + return [watchWalletStatusSaga] +} + +// single entry point to start all Sagas at once +export default function* rootSagas() { + console.log("rootSagas") + yield all([call(watchWalletStatusSaga)]); +} diff --git a/web/src/state/sagas/manageWallet.ts b/web/src/state/sagas/manageWallet.ts new file mode 100644 index 0000000..9f83933 --- /dev/null +++ b/web/src/state/sagas/manageWallet.ts @@ -0,0 +1,20 @@ +import { take } from "redux-saga/effects"; +import { getType } from "typesafe-actions"; +import { ManageWalletActions } from "../actions/manageWallet"; + +function* waitForMnemonicImport() { + console.log("waitForReindex -- /WalletImportMnemonic"); + for (;;) { + const { reindexComplete } = yield { + reindexComplete: take(getType(ManageWalletActions.walletComplete)) + }; + if (reindexComplete) { + console.log("waitForReindex complete"); + return; + } + } +} + +export function* watchWalletStatusSaga() { + yield waitForMnemonicImport(); +} diff --git a/web/src/state/shared/MapPropsToDispatchObj.ts b/web/src/state/shared/MapPropsToDispatchObj.ts new file mode 100644 index 0000000..eeff8aa --- /dev/null +++ b/web/src/state/shared/MapPropsToDispatchObj.ts @@ -0,0 +1,3 @@ +export type MapPropsToDispatchObj = { + [P in keyof T]:T[P] +} diff --git a/web/src/state/shared/PickedDispatchProps.ts b/web/src/state/shared/PickedDispatchProps.ts new file mode 100644 index 0000000..f46ca3b --- /dev/null +++ b/web/src/state/shared/PickedDispatchProps.ts @@ -0,0 +1,3 @@ +export type PickedDispatchProps = { + [P in K]: T[P] extends (...args: any[]) => any ? (...args: Parameters) => void : never; +}; diff --git a/web/src/state/store/index.ts b/web/src/state/store/index.ts new file mode 100644 index 0000000..6f2e89b --- /dev/null +++ b/web/src/state/store/index.ts @@ -0,0 +1,33 @@ +import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit"; +import createSagaMiddleware from "redux-saga"; +import { createInjectorsEnhancer } from "redux-injectors"; +import createReducer from "../reducers"; +import rootSagas from "../sagas"; + +export default function configureAppStore(initialState = {}) { + const reduxSagaMonitorOptions = {}; + const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions); + + const { run: runSaga } = sagaMiddleware; + + // sagaMiddleware: Makes redux-sagas work + const middlewares = [sagaMiddleware]; + + const enhancers = [ + createInjectorsEnhancer({ + createReducer, + runSaga + }) + ]; + + const store = configureStore({ + reducer: createReducer(), + middleware: [...getDefaultMiddleware(), ...middlewares], + preloadedState: initialState, + devTools: true, + enhancers + }); + + sagaMiddleware.run(rootSagas); + return store; +} diff --git a/web/src/state/store/manageWallet.ts b/web/src/state/store/manageWallet.ts new file mode 100644 index 0000000..ced46e5 --- /dev/null +++ b/web/src/state/store/manageWallet.ts @@ -0,0 +1,17 @@ +import { connect } from "react-redux"; +import { MapPropsToDispatchObj } from "../shared/MapPropsToDispatchObj"; +import { ManageWalletActions } from "../actions/manageWallet"; +import { WalletSetup, WalletSetupProps, WalletViewDispatch } from "../../components/wallet/Setup"; +import { RootState } from '../reducers'; + +const mapStateToProps = (state: RootState): WalletSetupProps => { + return { + complete: true, + onCancel: null, + onComplete: null, + }; +}; + +const mapDispatchToProps: MapPropsToDispatchObj = { ...ManageWalletActions }; + +export default connect(mapStateToProps, mapDispatchToProps)(WalletSetup); diff --git a/web/yarn.lock b/web/yarn.lock index 2604183..cde7216 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1011,6 +1011,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.1.tgz#b4116a6b6711d010b2dad3b7b6e43bf1b9954740" + integrity sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -1324,6 +1331,60 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== +"@redux-saga/core@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@redux-saga/core/-/core-1.1.3.tgz#3085097b57a4ea8db5528d58673f20ce0950f6a4" + integrity sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg== + dependencies: + "@babel/runtime" "^7.6.3" + "@redux-saga/deferred" "^1.1.2" + "@redux-saga/delay-p" "^1.1.2" + "@redux-saga/is" "^1.1.2" + "@redux-saga/symbols" "^1.1.2" + "@redux-saga/types" "^1.1.0" + redux "^4.0.4" + typescript-tuple "^2.2.1" + +"@redux-saga/deferred@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@redux-saga/deferred/-/deferred-1.1.2.tgz#59937a0eba71fff289f1310233bc518117a71888" + integrity sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ== + +"@redux-saga/delay-p@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@redux-saga/delay-p/-/delay-p-1.1.2.tgz#8f515f4b009b05b02a37a7c3d0ca9ddc157bb355" + integrity sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g== + dependencies: + "@redux-saga/symbols" "^1.1.2" + +"@redux-saga/is@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@redux-saga/is/-/is-1.1.2.tgz#ae6c8421f58fcba80faf7cadb7d65b303b97e58e" + integrity sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w== + dependencies: + "@redux-saga/symbols" "^1.1.2" + "@redux-saga/types" "^1.1.0" + +"@redux-saga/symbols@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@redux-saga/symbols/-/symbols-1.1.2.tgz#216a672a487fc256872b8034835afc22a2d0595d" + integrity sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ== + +"@redux-saga/types@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" + integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== + +"@reduxjs/toolkit@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.4.0.tgz#ee2e2384cc3d1d76780d844b9c2da3580d32710d" + integrity sha512-hkxQwVx4BNVRsYdxjNF6cAseRmtrkpSlcgJRr3kLUcHPIAMZAmMJkXmHh/eUEGTMqPzsYpJLM7NN2w9fxQDuGw== + dependencies: + immer "^7.0.3" + redux "^4.0.0" + redux-thunk "^2.3.0" + reselect "^4.0.0" + "@semantic-ui-react/event-stack@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@semantic-ui-react/event-stack/-/event-stack-3.1.1.tgz#3263d17511db81a743167fe45281a24b3eb6b3c8" @@ -1557,6 +1618,19 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/history@*": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -1638,6 +1712,24 @@ dependencies: "@types/react" "*" +"@types/react-redux@^7.1.9": + version "7.1.9" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3" + integrity sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + +"@types/react-router@^5.1.8": + version "5.1.8" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.8.tgz#4614e5ba7559657438e17766bb95ef6ed6acc3fa" + integrity sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg== + dependencies: + "@types/history" "*" + "@types/react" "*" + "@types/react@*", "@types/react@^16.9.0": version "16.9.49" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872" @@ -3184,6 +3276,13 @@ connect-history-api-fallback@^1.6.0: resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== +connected-react-router@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.8.0.tgz#ddc687b31d498322445d235d660798489fa56cae" + integrity sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg== + dependencies: + prop-types "^15.7.2" + console-browserify@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" @@ -5140,6 +5239,18 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -5154,6 +5265,13 @@ hoist-non-react-statics@^1.2.0: resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" integrity sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs= +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" @@ -5366,6 +5484,11 @@ immer@1.10.0: resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== +immer@^7.0.3: + version "7.0.9" + resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.9.tgz#28e7552c21d39dd76feccd2b800b7bc86ee4a62e" + integrity sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -5828,6 +5951,11 @@ is-wsl@^2.1.1: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -6731,7 +6859,7 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -6919,6 +7047,14 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +mini-create-react-context@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" + integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== + dependencies: + "@babel/runtime" "^7.5.5" + tiny-warning "^1.0.3" + mini-css-extract-plugin@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" @@ -7698,6 +7834,13 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -8830,7 +8973,7 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== -react-is@^16.12.0, react-is@^16.6.3, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6: +react-is@^16.12.0, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -8853,6 +8996,33 @@ react-popper@^1.3.7: typed-styles "^0.0.7" warning "^4.0.2" +react-redux@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985" + integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg== + dependencies: + "@babel/runtime" "^7.5.5" + hoist-non-react-statics "^3.3.0" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.9.0" + +react-router@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-scripts@3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.3.tgz#21de5eb93de41ee92cd0b85b0e1298d0bb2e6c51" @@ -9026,6 +9196,36 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redux-injectors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/redux-injectors/-/redux-injectors-1.3.0.tgz#7d283633428ccbe22e165903b60f432e63da6947" + integrity sha512-ZoyKf8Y0bRqpmJImaVO3jnDKuMXTzMDp3j+b0bqtSuPAgWcHD/2P9gRr4mI1EjgCiheIyQ/JJI8yLG29ijqRaw== + dependencies: + hoist-non-react-statics "^3.3.2" + invariant "^2.2.4" + lodash "^4.17.15" + redux "^4.0.5" + +redux-saga@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-1.1.3.tgz#9f3e6aebd3c994bbc0f6901a625f9a42b51d1112" + integrity sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw== + dependencies: + "@redux-saga/core" "^1.1.3" + +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.0, redux@^4.0.4, redux@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -9199,6 +9399,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +reselect@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" + integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -9216,6 +9421,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve-url-loader@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz#28931895fa1eab9be0647d3b2958c100ae3c0bf0" @@ -10203,6 +10413,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -10338,6 +10553,16 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -10491,6 +10716,30 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typesafe-actions@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/typesafe-actions/-/typesafe-actions-5.1.0.tgz#9afe8b1e6a323af1fd59e6a57b11b7dd6623d2f1" + integrity sha512-bna6Yi1pRznoo6Bz1cE6btB/Yy8Xywytyfrzu/wc+NFW3ZF0I+2iCGImhBsoYYCOWuICtRO4yHcnDlzgo1AdNg== + +typescript-compare@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/typescript-compare/-/typescript-compare-0.0.2.tgz#7ee40a400a406c2ea0a7e551efd3309021d5f425" + integrity sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA== + dependencies: + typescript-logic "^0.0.0" + +typescript-logic@^0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/typescript-logic/-/typescript-logic-0.0.0.tgz#66ebd82a2548f2b444a43667bec120b496890196" + integrity sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q== + +typescript-tuple@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/typescript-tuple/-/typescript-tuple-2.2.1.tgz#7d9813fb4b355f69ac55032e0363e8bb0f04dad2" + integrity sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q== + dependencies: + typescript-compare "^0.0.2" + typescript@~3.7.2: version "3.7.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" @@ -10693,6 +10942,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"