diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..09c2381
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,37 @@
+# Javascript Node CircleCI 2.0 configuration file
+#
+# Check https://circleci.com/docs/2.0/language-javascript/ for more details
+#
+version: 2
+jobs:
+ build:
+ docker:
+ # specify the version you desire here
+ - image: circleci/node:7.10
+
+ # Specify service dependencies here if necessary
+ # CircleCI maintains a library of pre-built images
+ # documented at https://circleci.com/docs/2.0/circleci-images/
+ # - image: circleci/mongo:3.4.4
+
+ working_directory: ~/repo
+
+ steps:
+ - checkout
+
+ # Download and cache dependencies
+ - restore_cache:
+ keys:
+ - v1-dependencies-{{ checksum "package.json" }}
+ # fallback to using the latest cache if no exact match is found
+ - v1-dependencies-
+
+ - run: yarn install
+
+ - save_cache:
+ paths:
+ - node_modules
+ key: v1-dependencies-{{ checksum "package.json" }}
+
+ # run tests!
+ - run: yarn test
diff --git a/.gitignore b/.gitignore
index beee1ef..f61f58f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ dist
*.sublime-workspace
path.sh
examples/config.json
+
+.nyc_output
diff --git a/README.md b/README.md
index cf2ab2d..884751b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# React Cognito
+## Build status
+
+
You can now use Amazon Cognito to handle authentication and authorization for
your mobile and web applications. This is particularly useful for serverless
single-page applications (SPAs). SPAs can be hosted in S3 buckets and use AWS
@@ -62,4 +65,3 @@ User Pool. Contains no secret material.
#### config
The configuration provided by the application, used to contact Cognito.
-
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..e2709d5
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,119 @@
+{
+ "name": "react-cognito-mm",
+ "version": "1.6.2",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "0.4.19"
+ }
+ },
+ "fbjs": {
+ "version": "0.8.16",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
+ "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.17"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "isomorphic-fetch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "1.7.3",
+ "whatwg-fetch": "2.0.3"
+ }
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+ },
+ "loose-envify": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
+ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "requires": {
+ "js-tokens": "3.0.2"
+ }
+ },
+ "node-fetch": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "requires": {
+ "encoding": "0.1.12",
+ "is-stream": "1.1.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "2.0.6"
+ }
+ },
+ "prop-types": {
+ "version": "15.6.0",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz",
+ "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1"
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+ },
+ "ua-parser-js": {
+ "version": "0.7.17",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",
+ "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="
+ },
+ "whatwg-fetch": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
+ "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
+ }
+ }
+}
diff --git a/package.json b/package.json
index 0026718..3fc0a08 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "react-cognito",
- "scope": "winjer",
- "version": "1.5.3",
+ "name": "react-cognito-mm",
+ "scope": "millarm",
+ "version": "1.6.15",
"description": "Use Amazon Cognito with React and Redux",
"main": "dist/react-cognito.js",
"repository": {
@@ -24,17 +24,16 @@
"scripts": {
"lint": "eslint ./src",
"lintfix": "eslint ./src --fix",
- "testonly": "PWD=$(pwd) NODE_ENV=test mocha $npm_package_options_mocha || true",
+ "testonly": "PWD=$(pwd) NODE_ENV=test nyc --reporter=text mocha $npm_package_options_mocha || true",
"debug": "PWD=$(pwd) NODE_ENV=test mocha --debug-brk --inspect $npm_package_options_mocha",
"test": "npm run lint && npm run testonly",
"test-watch": "npm run testonly -- --watch --watch-extensions js",
"examples": "[ -d examples/htdocs/dist ] || mkdir examples/htdocs/dist; babel --plugins transform-es2015-modules-umd src --ignore __tests__ examples/src --out-file examples/htdocs/dist/bundle.js",
"doc": "esdoc",
- "prepublish": "webpack -d; webpack -p"
+ "prepublish": "webpack -d; webpack -p",
+ "prepare": "webpack -d; webpack -p"
},
"devDependencies": {
- "amazon-cognito-identity-js": "1.19.0",
- "aws-sdk": "2.92.0",
"babel": "^6.5.2",
"babel-cli": "^6.18.0",
"babel-core": "^6.21.0",
@@ -45,7 +44,7 @@
"babel-polyfill": "^6.7.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
- "babel-preset-stage-2": "^6.5.0",
+ "babel-preset-stage-2": "^6.24.1",
"chai": "^3.5.0",
"chai-as-promised": "^6.0.0",
"enzyme": "^2.2.0",
@@ -65,21 +64,26 @@
"local-web-server": "^1.2.6",
"mocha": "^3.2.0",
"nodemon": "^1.9.1",
- "react": "^15.4.1",
+ "nyc": "^11.2.1",
"react-addons-test-utils": "^15.0.0",
- "react-dom": "^15.0.0",
- "react-redux": "^5.0.1",
- "redux": "^3.6.0",
"sinon": "^2.2.0",
"sinon-chai": "^2.10.0",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
},
"peerDependencies": {
- "react": "~0.14.8 || ^15.0.0",
- "react-dom": "~0.14.8 || ^15.0.0"
+ "react": "~0.14.8 || ^15.0.0 || ^16.0.0",
+ "react-dom": "~0.14.8 || ^15.0.0 || ^16.0.0"
},
"dependencies": {
- "babel-runtime": "^6.6.1"
+ "amazon-cognito-identity-js": "^3.0.11",
+ "aws-sdk": "^2.332.0",
+ "babel-runtime": "^6.6.1",
+ "flow": "^0.2.3",
+ "prop-types": "^15.6.0",
+ "react": "^15.4.1",
+ "react-dom": "^15.0.0",
+ "react-redux": "^5.0.6",
+ "redux": "^3.6.0"
}
}
diff --git a/src/Logout.jsx b/src/Logout.jsx
index 136ef01..5ff65e7 100644
--- a/src/Logout.jsx
+++ b/src/Logout.jsx
@@ -1,6 +1,16 @@
-import React, { PropTypes } from 'react';
+/* eslint-disable react/prop-types */
+import React from 'react';
import { Action } from './actions';
+type Props = {
+ children: any,
+ onLogout: () => void,
+};
+
+type State = {
+ cognito: { user: { signOut: () => void } },
+};
+
/**
* Container for logout behaviour.
* @example
@@ -8,8 +18,7 @@ import { Action } from './actions';
*
*
*/
-export class Logout extends React.Component {
-
+export class Logout extends React.Component {
/**
* Passed to child element as onClick prop.
* Signs the user out, and then dispatches the logout action
@@ -23,7 +32,7 @@ export class Logout extends React.Component {
event.preventDefault();
store.dispatch(Action.logout());
this.props.onLogout();
- }
+ };
/**
* renders the child element, adding an onClick property
@@ -34,14 +43,6 @@ export class Logout extends React.Component {
});
}
}
-Logout.contextTypes = {
- store: PropTypes.object,
-};
-Logout.propTypes = {
- children: React.PropTypes.any.isRequired,
- onLogout: React.PropTypes.func,
-};
Logout.defaultProps = {
onLogout: () => {},
};
-
diff --git a/src/actions.js b/src/actions.js
index 14c6832..2ea0b5a 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -25,6 +25,16 @@ const Action = {
attributes,
}),
+ refresh: user => ({
+ type: 'COGNITO_REFRESH',
+ user,
+ }),
+
+ error: error => ({
+ type: 'COGNITO_ERROR',
+ error,
+ }),
+
logout: () => ({
type: 'COGNITO_LOGOUT',
}),
@@ -39,6 +49,12 @@ const Action = {
error,
}),
+ registerFailure: (userName, error) => ({
+ type: 'COGNITO_REGISTER_FAILURE',
+ userName,
+ error,
+ }),
+
mfaRequired: user => ({
type: 'COGNITO_LOGIN_MFA_REQUIRED',
user,
diff --git a/src/auth.js b/src/auth.js
index 8304673..87fdad5 100644
--- a/src/auth.js
+++ b/src/auth.js
@@ -1,5 +1,5 @@
-import { CognitoUser, AuthenticationDetails } from 'amazon-cognito-identity-js';
-import { CognitoIdentityCredentials } from 'aws-sdk/global';
+import { CognitoUser, AuthenticationDetails, CognitoRefreshToken } from 'amazon-cognito-identity-js';
+import AWS from 'aws-sdk/global';
import { Action } from './actions';
import { getUserAttributes, mkAttrList, sendAttributeVerificationCode } from './attributes';
import { buildLogins, getGroups } from './utils';
@@ -12,17 +12,21 @@ import { buildLogins, getGroups } from './utils';
*/
const emailVerificationFlow = (user, attributes) =>
new Promise(resolve =>
- sendAttributeVerificationCode(user, 'email').then((required) => {
- if (required) {
- resolve(Action.emailVerificationRequired(attributes));
- } else {
- // dead end?
- resolve(Action.loggingIn(attributes));
- }
- }, (error) => {
- // some odd classes of error here
- resolve(Action.emailVerificationFailed(error, attributes));
- }));
+ sendAttributeVerificationCode(user, 'email').then(
+ (required) => {
+ if (required) {
+ resolve(Action.emailVerificationRequired(attributes));
+ } else {
+ // dead end?
+ resolve(Action.loggingIn(attributes));
+ }
+ },
+ (error) => {
+ // some odd classes of error here
+ resolve(Action.emailVerificationFailed(error, attributes));
+ },
+ ),
+ );
/**
* logs in to the federated identity pool with a JWT
@@ -34,10 +38,10 @@ const emailVerificationFlow = (user, attributes) =>
const refreshIdentityCredentials = (username, jwtToken, config) =>
new Promise((resolve, reject) => {
const logins = buildLogins(username, jwtToken, config);
- const creds = new CognitoIdentityCredentials(logins, { region: config.region });
+ const creds = new AWS.CognitoIdentityCredentials(logins, { region: config.region });
creds.refresh((error) => {
if (error) {
- reject(error.message);
+ reject(error);
} else {
resolve(creds);
}
@@ -52,18 +56,24 @@ const refreshIdentityCredentials = (username, jwtToken, config) =>
* @return {Promise