[
  {
    "path": ".browserslistrc",
    "content": "> 1%\nlast 2 versions\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    node: true\n  },\n  extends: [\"plugin:vue/essential\", \"@vue/prettier\"],\n  rules: {\n    \"no-console\": process.env.NODE_ENV === \"production\" ? \"error\" : \"off\",\n    \"no-debugger\": process.env.NODE_ENV === \"production\" ? \"error\" : \"off\"\n  },\n  parserOptions: {\n    parser: \"babel-eslint\"\n  },\n  overrides: [\n    {\n      files: [\n        \"**/__tests__/*.{j,t}s?(x)\",\n        \"**/tests/unit/**/*.spec.{j,t}s?(x)\"\n      ],\n      env: {\n        jest: true\n      }\n    }\n  ]\n};\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "name: Node CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [10.x, 12.x]\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - name: npm install, build, and test\n      run: |\n        yarn\n        yarn run build --if-present\n        yarn jest\n      env:\n        CI: true\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw*\n\n# Don't commit your aws mobile configuration file\n.envrc"
  },
  {
    "path": ".nvmrc",
    "content": "10\n"
  },
  {
    "path": "LICENSE.md",
    "content": "   Copyright 2018 Mark Wolfe\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "ci: clean build deploy\n\nclean:\n\trm -rf dist\n\nbuild:\n\tyarn build\n\ndeploy:\n\taws s3 sync dist/ s3://$(S3_HOSTING_BUCKET)/ --delete --acl public-read\n\taws cloudfront create-invalidation --distribution-id $(DISTRIBUTION_ID) --paths '/*'"
  },
  {
    "path": "README.md",
    "content": "# cognito-vue-bootstrap\n\nThis application illustrates how to use the [Amazon Amplify](https://github.com/aws/aws-amplify) with [vue.js](https://vuejs.org/), it includes signup, signin, signout, recover password and account verification using email or sms codes. It uses [bootstrap-vue](https://bootstrap-vue.js.org/) for layout.\n\n# overview\n\nThis example application currently illustrates the following:\n\n* Sign Up for an account\n* Verify your account by entering verification code which has been sent to you via emailed or SMS\n* Dashboard which requires authentication to access\n* Change Password\n* Recover Password using verification code which has been sent to you via emailed or SMS\n* Sign In to the application\n* Sign Out of the application\n\nDemo version is located at https://cognito-vue-bootstrapv2.wolfe.id.au/\n\n# Build Setup\n\nBefore you start have a read over [What is Amazon Cognito?](http://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html)\n\nTo setup this project you first need to configure an aws mobile project using the following snapshot [CognitoVue](https://console.aws.amazon.com/mobilehub/home#/snapshot/ef9bu3t7nsa8uz).\n\nFor more information on this process see [Exporting and Importing AWS Mobile Hub Projects](https://docs.aws.amazon.com/aws-mobile/latest/developerguide/project-import-export.html)\n\nOnce you have imported the project you will have created:\n\n* An S3 bucket with Cloudfront for your web application.\n* A Cognito pool to store your users\n* An analytics project to capture metrics on your users login / failure ect.\n\nClick on the integrate button in your aws mobile project, the download and extract the cloud config zip file, find `aws-exports.js` inside, and replace this file in `src/` directory.\n\nI use [yarn](https://yarnpkg.com/) to build and run this project.\n\n``` bash\n# install dependencies\nyarn install\n\n# serve with hot reload at localhost:8080\nyarn serve\n\n# build for production with minification\nyarn build\n```\n\nSync all the files from your `dist` directory up to the S3 hosting bucket within your AWS Mobile project using the following command.\n\n```\naws --region ap-southeast-2 s3 sync dist/ s3://cognitovuebootstrap-hosting-mobilehub-XXXXXXXXXX/ --delete --acl public-read\n```\n\n# hosting configuration notes\n\nTo host a website on a custom URL using AWS mobile I have found some changes to the current setup. Navigating to the buckets and CDN configuration is done via the `Hosting And Streaming` panel in the mobile project UI.\n\n* disable website hosting on the hosting S3 bucket\n* add an Error Page which sends any 404 (not found) errors to `/index.html` in cloudfront\n* enable redirect http -> https on the origin\n* configure a route53 domain for your website\n* configure a AWS Certificate Manager (ACM) certificate for your domain\n* add an A record in route53 of type `alias` pointing to your Cloudfront distribution, then update the origin domain name to match the FQDN.\n\nFor a more detailed explanation on how things work, checkout:\n\n* [AWS Amplify Documentation](https://aws.github.io/aws-amplify/)\n* [AWS Amplify Modularization](https://github.com/aws-amplify/amplify-js/wiki/Amplify-modularization)\n* [docs for vue-cli](https://cli.vuejs.org/)\n* [docs for vue-router](http://router.vuejs.org/en/)\n* [docs for vuex](https://vuex.vuejs.org/)\n\n# License\n\nThis project is released under the Apache License, Version 2.0.\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: [\"@vue/cli-plugin-babel/preset\"]\n};\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  preset: \"@vue/cli-plugin-unit-jest\"\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"cognito-vue-bootstrap\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"test:unit\": \"vue-cli-service test:unit\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"@aws-amplify/auth\": \"^1.5.0\",\n    \"bootstrap-vue\": \"^2.0.4\",\n    \"core-js\": \"^3.3.2\",\n    \"vue\": \"^2.6.10\",\n    \"vue-awesome\": \"^3.5.4\",\n    \"vue-resource\": \"^1.5.1\",\n    \"vue-router\": \"^3.1.3\",\n    \"vuex\": \"^3.0.1\",\n    \"vuex-localstorage\": \"^1.0.0\"\n  },\n  \"devDependencies\": {\n    \"@testing-library/vue\": \"^4.1.0\",\n    \"@vue/cli-plugin-babel\": \"^4.0.0\",\n    \"@vue/cli-plugin-eslint\": \"^4.0.0\",\n    \"@vue/cli-plugin-router\": \"^4.0.0\",\n    \"@vue/cli-plugin-unit-jest\": \"^4.0.0\",\n    \"@vue/cli-plugin-vuex\": \"^4.0.0\",\n    \"@vue/cli-service\": \"^4.0.0\",\n    \"@vue/eslint-config-prettier\": \"^5.0.0\",\n    \"@vue/test-utils\": \"1.0.0-beta.29\",\n    \"babel-eslint\": \"^10.0.3\",\n    \"eslint\": \"^5.16.0\",\n    \"eslint-plugin-prettier\": \"^3.1.1\",\n    \"eslint-plugin-vue\": \"^5.0.0\",\n    \"prettier\": \"^1.18.2\",\n    \"vue-template-compiler\": \"^2.6.10\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    autoprefixer: {}\n  }\n};\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title>cognito-vue-bootstrapv3</title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but cognito-vue-bootstrapv3 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "src/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <b-container class=\"main\" fluid>\n      <v-menu />\n      <router-view />\n      <v-footer />\n    </b-container>\n  </div>\n</template>\n\n<script>\nimport Vue from \"vue\";\nimport Menu from \"@/components/Menu.vue\";\nimport Footer from \"@/components/Footer.vue\";\nimport Icon from \"vue-awesome/components/Icon\";\n\nVue.component(\"v-menu\", Menu);\nVue.component(\"v-footer\", Footer);\nVue.component(\"v-icon\", Icon);\n\nexport default {\n  name: \"App\"\n};\n</script>\n\n<style>\n@import \"~bootstrap/dist/css/bootstrap.css\";\n@import \"~bootstrap-vue/dist/bootstrap-vue.css\";\n\n#app {\n  font-family: \"Avenir\", Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  margin: 0;\n  padding: 0;\n}\n\n.main {\n  margin: 0;\n  padding: 0;\n}\n\n.b-main-content {\n  padding-top: 1.5rem;\n  padding-bottom: 1.5rem;\n  margin-right: 0;\n  margin-left: 0;\n}\n\n.b-form-1 {\n  padding-top: 1.5rem;\n  padding-bottom: 1.5rem;\n  margin-right: 0;\n  margin-left: 0;\n  border-width: 0.2rem;\n}\n</style>\n"
  },
  {
    "path": "src/aws-exports.js",
    "content": "const config = {\n  // To get the AWS Credentials, you need to configure\n  // the Auth module with your Cognito Federated Identity Pool\n  Auth: {\n    identityPoolId: process.env.IDENTITY_POOL_ID,\n    region: process.env.AWS_REGION,\n    userPoolId: process.env.USER_POOL_ID,\n    userPoolWebClientId: process.env.USER_POOL_WEB_CLIENT_ID,\n    mandatorySignIn: false,\n    clientMetadata: { app: \"cognito-vue-bootstrap\" }\n  },\n  Analytics: {\n    disabled: false,\n    autoSessionRecord: true,\n    AWSPinpoint: {\n      appId: process.env.PINPOINT_APP_ID,\n      region: process.env.AWS_REGION\n    }\n  }\n};\n\nexport default config;\n"
  },
  {
    "path": "src/components/Footer.vue",
    "content": "<template>\n  <footer class=\"bd-footer\">\n    <b-container>\n      <b-row class=\"justify-content-md-center\">\n        <div class=\"bd-footer-copyright\">© 2018 Company, Inc.</div>\n      </b-row>\n    </b-container>\n  </footer>\n</template>\n\n<script>\nexport default {};\n</script>\n\n<style>\n.bd-footer {\n  margin-top: 2em;\n  border-top: 0.2rem #f7f7f7 solid !important;\n}\n\n.bd-footer-copyright {\n  padding-top: 1rem;\n  padding-bottom: 1rem;\n}\n</style>\n"
  },
  {
    "path": "src/components/Menu.vue",
    "content": "<template>\n  <b-navbar toggleable=\"md\" type=\"dark\">\n    <b-navbar-toggle target=\"nav_collapse\" />\n    <b-navbar-brand to=\"/\">Cognito Bootstrap</b-navbar-brand>\n    <b-navbar-nav>\n      <b-nav-item to=\"/dashboard\">Dashboard</b-nav-item>\n    </b-navbar-nav>\n    <b-navbar-nav class=\"ml-auto\">\n      <b-nav-item v-if=\"!isAuthenticated\" class=\"nav-btn\" to=\"/signIn\"\n        ><span class=\"nav-username\">Sign In</span></b-nav-item\n      >\n      <b-nav-item-dropdown v-if=\"isAuthenticated\" right>\n        <template slot=\"button-content\">\n          <v-icon name=\"regular/user-circle\" /><strong class=\"nav-username\">{{\n            user.username\n          }}</strong>\n        </template>\n        <b-row class=\"justify-content-md-center\" style=\"margin:5px\">\n          <b-dropdown-item to=\"/changePassword\"\n            ><span class=\"nav-username\">Change Password</span></b-dropdown-item\n          >\n          <b-dropdown-item to=\"/signOut\"\n            ><v-icon name=\"sign-out-alt\" /><span class=\"nav-username\"\n              >Sign Out</span\n            ></b-dropdown-item\n          >\n        </b-row>\n      </b-nav-item-dropdown>\n      <b-nav-item class=\"nav-btn\" href=\"https://twitter.com/wolfeidau\"\n        ><v-icon name=\"brands/twitter\"\n      /></b-nav-item>\n      <b-nav-item\n        class=\"nav-btn\"\n        href=\"https://github.com/wolfeidau/cognito-vue-bootstrap\"\n        ><v-icon name=\"brands/github\"\n      /></b-nav-item>\n    </b-navbar-nav>\n  </b-navbar>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\n\nimport \"vue-awesome/icons/regular/user-circle\";\nimport \"vue-awesome/icons/sign-out-alt\";\nimport \"vue-awesome/icons/brands/twitter\";\nimport \"vue-awesome/icons/brands/github\";\n\nexport default {\n  name: \"Navbar\",\n  computed: {\n    ...mapState({\n      user: state => state.auth.user,\n      isAuthenticated: state => state.auth.isAuthenticated\n    })\n  },\n  methods: {\n    signIn() {\n      this.$store.dispatch(\"signIn\");\n    }\n  }\n};\n</script>\n\n<style scoped>\n.navbar {\n  background-color: #563d7c;\n}\n.navbar-nav .nav-link {\n  color: #cbbde2;\n}\n.nav-username {\n  padding-left: 0.5em;\n  padding-right: 0.5em;\n}\n</style>\n"
  },
  {
    "path": "src/components/auth/Alert.vue",
    "content": "<template>\n  <b-alert\n    :show=\"hasAuthenticationStatus\"\n    :variant=\"authenticationStatus.variant\"\n    >{{ authenticationStatus.message }}.</b-alert\n  >\n</template>\n\n<script>\nimport { mapGetters } from \"vuex\";\n\nexport default {\n  mounted() {\n    // clear existing status message\n    this.$store.dispatch(\"auth/clearAuthenticationStatus\");\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"authenticationStatus\", \"hasAuthenticationStatus\"])\n  }\n};\n</script>\n"
  },
  {
    "path": "src/main.js",
    "content": "import Vue from \"vue\";\nimport BootstrapVue from \"bootstrap-vue\";\nimport App from \"@/App.vue\";\nimport router from \"@/router\";\nimport store from \"@/store\";\nimport Auth from \"@aws-amplify/auth\";\nimport AuthConfig from \"@/aws-exports\";\n\nAuth.configure(AuthConfig);\n\nVue.use(BootstrapVue);\n\nVue.config.productionTip = false;\n\nnew Vue({\n  router,\n  store,\n  el: \"#app\",\n  render: h => h(App)\n});\n"
  },
  {
    "path": "src/pages/Dashboard.vue",
    "content": "<template>\n  <b-container>\n    <div class=\"b-main-content\">\n      <h2>Cognito Bootstrap Vue</h2>\n      <p>You are logged in as {{ user.username }}.</p>\n    </div>\n  </b-container>\n</template>\n\n<script>\nimport { mapState } from \"vuex\";\n\nexport default {\n  computed: {\n    ...mapState({\n      user: state => state.auth.user\n    })\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/Home.vue",
    "content": "<template>\n  <b-container>\n    <div class=\"b-main-content\">\n      <h2>Cognito Bootstrap Vue</h2>\n      <p>\n        This site provides an example of how to use\n        <b-link href=\"https://aws.amazon.com/cognito\">Amazon Cognito</b-link>\n        with <b-link href=\"https://vuejs.org\">Vue.js</b-link>\n      </p>\n      <p>To give it a try:</p>\n      <ol>\n        <li>\n          Sign up using your email address, this will send through an activation\n          code.\n        </li>\n        <li>\n          Once you get the activation code enter it with your email address.\n        </li>\n        <li>Sign in with your credentials.</li>\n        <li>Request a password reset to recover an account.</li>\n        <li>Change your password.</li>\n      </ol>\n      <p>\n        <b-button variant=\"outline-dark\" to=\"signUp\">Sign Up</b-button>\n      </p>\n      <p>\n        The full source code for this example application is available here:\n      </p>\n      <ul>\n        <li>\n          <b-link href=\"https://github.com/wolfeidau/cognito-vue-bootstrap\"\n            >https://github.com/wolfeidau/cognito-vue-bootstrap</b-link\n          >\n        </li>\n      </ul>\n    </div>\n  </b-container>\n</template>\n\n<script>\nexport default {};\n</script>\n"
  },
  {
    "path": "src/pages/auth/ChangePassword.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Change Password</h2>\n          <p>Request a password change.</p>\n          <b-form @submit.prevent=\"passwordChange\">\n            <b-form-group\n              label=\"Current Password:\"\n              label-for=\"currentPasswordInput\"\n            >\n              <b-form-input\n                id=\"currentPasswordInput\"\n                type=\"password\"\n                v-model=\"currentPassword\"\n                required\n                placeholder=\"Enter Current Password\"\n              />\n            </b-form-group>\n            <b-form-group label=\"New Password:\" label-for=\"newPasswordInput\">\n              <b-form-input\n                id=\"newPasswordInput\"\n                type=\"password\"\n                v-model=\"newPassword\"\n                required\n                placeholder=\"Enter New Password\"\n              />\n            </b-form-group>\n            <b-button type=\"submit\" variant=\"primary\">Submit</b-button>\n          </b-form>\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\n\nimport { mapGetters } from \"vuex\";\nimport router from \"@/router\";\nimport store from \"@/store\";\n\nimport Alert from \"@/components/auth/Alert.vue\";\n\nVue.component(\"v-alert\", Alert);\n\nexport default {\n  data() {\n    return {\n      currentPassword: \"\",\n      newPassword: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async passwordChange() {\n      await store.dispatch(\"auth/passwordChange\", {\n        currentPassword: this.currentPassword,\n        newPassword: this.newPassword\n      });\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"dashboard\");\n      }\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/auth/ConfirmPasswordReset.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Confirm Reset Password</h2>\n          <p>\n            Confirm a password reset using the code you recieved via emailed.\n          </p>\n          <b-form-group label=\"Username:\" label-for=\"usernameInput\">\n            <b-form-input\n              id=\"usernameInput\"\n              type=\"text\"\n              v-model=\"username\"\n              required\n              autofocus\n              placeholder=\"Enter username\"\n            />\n          </b-form-group>\n          <b-form-group label=\"Code:\" label-for=\"codeInput\">\n            <b-form-input\n              id=\"codeInput\"\n              type=\"password\"\n              v-model=\"code\"\n              required\n              placeholder=\"Enter Code\"\n            />\n          </b-form-group>\n          <b-form-group label=\"Password:\" label-for=\"passwordInput\">\n            <b-form-input\n              id=\"passwordInput\"\n              type=\"password\"\n              v-model=\"password\"\n              required\n              placeholder=\"Enter Code\"\n            />\n          </b-form-group>\n          <b-button\n            type=\"submit\"\n            variant=\"primary\"\n            @click=\"confirmPasswordReset\"\n            >Submit</b-button\n          >\n          <b-button variant=\"primary\" @click=\"passwordResetResend\"\n            >Resend Code</b-button\n          >\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\n\nimport { mapGetters } from \"vuex\";\nimport router from \"@/router\";\nimport store from \"@/store\";\n\nimport Alert from \"@/components/auth/Alert.vue\";\n\nVue.component(\"v-alert\", Alert);\n\nexport default {\n  data() {\n    return {\n      username: \"\",\n      code: \"\",\n      password: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async confirmPasswordReset() {\n      await store.dispatch(\"auth/confirmPasswordReset\", {\n        username: this.username,\n        code: this.code,\n        password: this.password\n      });\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"signIn\");\n      }\n    },\n    async passwordResetResend() {\n      await store.dispatch(\"auth/passwordReset\", {\n        username: this.username\n      });\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/auth/ConfirmSignUp.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Confirm Sign Up</h2>\n          <b-form-group label=\"Username:\" label-for=\"usernameInput\">\n            <b-form-input\n              id=\"usernameInput\"\n              type=\"text\"\n              v-model=\"username\"\n              required\n              autofocus\n              placeholder=\"Enter username\"\n            />\n          </b-form-group>\n          <b-form-group label=\"Code:\" label-for=\"codeInput\">\n            <b-form-input\n              id=\"codeInput\"\n              type=\"password\"\n              v-model=\"code\"\n              required\n              placeholder=\"Enter Code\"\n            />\n          </b-form-group>\n          <b-button type=\"submit\" variant=\"primary\" @click=\"confirmSignUp\"\n            >Submit</b-button\n          >\n          <b-button variant=\"primary\" @click=\"confirmResend\"\n            >Resend Code</b-button\n          >\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\n\nimport { mapGetters } from \"vuex\";\nimport router from \"@/router\";\nimport store from \"@/store\";\n\nimport Alert from \"@/components/auth/Alert.vue\";\n\nVue.component(\"v-alert\", Alert);\n\nexport default {\n  data() {\n    return {\n      username: \"\",\n      code: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async confirmSignUp() {\n      await store.dispatch(\"auth/confirmSignUp\", {\n        username: this.username,\n        code: this.code\n      });\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"signIn\");\n      }\n    },\n    async confirmResend() {\n      await store.dispatch(\"auth/confirmResend\", {\n        username: this.username\n      });\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/auth/PasswordReset.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Reset Password</h2>\n          <p>Request a password reset code via email.</p>\n          <b-form @submit.prevent=\"passwordReset\">\n            <b-form-group label=\"Username:\" label-for=\"usernameInput\">\n              <b-form-input\n                id=\"usernameInput\"\n                type=\"text\"\n                v-model=\"username\"\n                required\n                autofocus\n                placeholder=\"Enter username\"\n              />\n            </b-form-group>\n            <b-button type=\"submit\" variant=\"primary\">Submit</b-button>\n          </b-form>\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\n\nimport { mapGetters } from \"vuex\";\nimport router from \"@/router\";\nimport store from \"@/store\";\n\nimport Alert from \"@/components/auth/Alert.vue\";\n\nVue.component(\"v-alert\", Alert);\n\nexport default {\n  data() {\n    return {\n      username: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async passwordReset() {\n      await store.dispatch(\"auth/passwordReset\", {\n        username: this.username\n      });\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"confirmPasswordReset\");\n      }\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/auth/SignIn.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Sign In</h2>\n          <p>Sign into this site.</p>\n          <b-form @submit.prevent=\"signIn\">\n            <b-form-group label=\"Email:\" label-for=\"emailInput\">\n              <b-form-input\n                id=\"emailInput\"\n                type=\"email\"\n                v-model=\"email\"\n                required\n                placeholder=\"Enter email\"\n              />\n            </b-form-group>\n            <b-form-group label=\"Password:\" label-for=\"passwordInput\">\n              <b-form-input\n                id=\"passwordInput\"\n                type=\"password\"\n                v-model=\"pass\"\n                required\n                placeholder=\"Enter Password\"\n              />\n            </b-form-group>\n            <b-button type=\"submit\" variant=\"primary\">Submit</b-button>\n          </b-form>\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <p>\n          <b-link to=\"signUp\">Create an account</b-link> or\n          <b-link to=\"passwordReset\">reset password</b-link>\n        </p>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\nimport { mapGetters } from \"vuex\";\nimport router from \"@/router\";\nimport store from \"@/store\";\n\nimport Alert from \"@/components/auth/Alert.vue\";\n\nVue.component(\"v-alert\", Alert);\n\nexport default {\n  data() {\n    return {\n      email: \"\",\n      pass: \"\"\n    };\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async signIn() {\n      await store.dispatch(\"auth/signIn\", {\n        username: this.email,\n        password: this.pass\n      });\n\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"dashboard\");\n      }\n    }\n  }\n};\n</script>\n\n<style></style>\n"
  },
  {
    "path": "src/pages/auth/SignOut.vue",
    "content": "<template>\n  <b-row class=\"justify-content-md-center\">\n    <b-col cols=\"8\">\n      <h2>Sign Out...</h2>\n    </b-col>\n  </b-row>\n</template>\n\n<script>\nimport router from \"@/router\";\n\nexport default {\n  async created() {\n    await this.$store.dispatch(\"auth/signOut\");\n    router.push(\"/\");\n  }\n};\n</script>\n"
  },
  {
    "path": "src/pages/auth/SignUp.vue",
    "content": "<template>\n  <b-container>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <div class=\"b-form-1\">\n          <h2>Sign Up</h2>\n          <p>Sign up for an account.</p>\n          <b-form @submit.prevent=\"signUp\">\n            <b-form-group label=\"Username:\" label-for=\"usernameInput\">\n              <b-form-input\n                id=\"usernameInput\"\n                type=\"text\"\n                v-model=\"username\"\n                required\n                placeholder=\"Enter username\"\n              />\n            </b-form-group>\n            <b-form-group label=\"Name:\" label-for=\"nameInput\">\n              <b-form-input\n                id=\"nameInput\"\n                type=\"text\"\n                v-model=\"name\"\n                required\n                placeholder=\"Enter your full name\"\n              />\n            </b-form-group>\n            <b-form-group label=\"Email:\" label-for=\"emailInput\">\n              <b-form-input\n                id=\"emailInput\"\n                type=\"email\"\n                v-model=\"email\"\n                required\n                placeholder=\"Enter email\"\n              />\n            </b-form-group>\n            <b-form-group label=\"Password:\" label-for=\"passwordInput\">\n              <b-form-input\n                id=\"passwordInput\"\n                type=\"password\"\n                v-model=\"pass\"\n                required\n                placeholder=\"Enter Password\"\n              />\n            </b-form-group>\n            <b-button type=\"submit\" variant=\"primary\">Submit</b-button>\n          </b-form>\n        </div>\n      </b-col>\n    </b-row>\n    <b-row class=\"justify-content-md-center\">\n      <b-col cols=\"4\">\n        <v-alert />\n      </b-col>\n    </b-row>\n  </b-container>\n</template>\n\n<script>\nimport Vue from \"vue\";\nimport router from \"@/router\";\nimport { mapGetters } from \"vuex\";\nimport Alert from \"@/components/auth/Alert.vue\";\nimport Amplify from \"@aws-amplify/core\";\n\nconst Logger = Amplify.Logger;\n\nVue.component(\"v-alert\", Alert);\n\nconst logger = new Logger(\"SignUpPage\");\n\nexport default {\n  data() {\n    return {\n      username: \"\",\n      email: \"\",\n      name: \"\",\n      pass: \"\"\n    };\n  },\n  mounted() {\n    // clear existing status message\n    this.$store.dispatch(\"auth/clearAuthenticationStatus\");\n  },\n  computed: {\n    ...mapGetters(\"auth\", [\"hasAuthenticationStatus\"])\n  },\n  methods: {\n    async signUp() {\n      logger.debug(\"sign-up\");\n      await this.$store.dispatch(\"auth/signUp\", {\n        username: this.username,\n        password: this.pass,\n        attributes: {\n          name: this.name,\n          email: this.email\n        }\n      });\n\n      if (!this.hasAuthenticationStatus) {\n        router.push(\"confirmSignUp\");\n      }\n    }\n  }\n};\n</script>\n"
  },
  {
    "path": "src/router/index.js",
    "content": "import Vue from \"vue\";\nimport Router from \"vue-router\";\nimport Home from \"@/pages/Home.vue\";\nimport Dashboard from \"@/pages/Dashboard.vue\";\nimport SignIn from \"@/pages/auth/SignIn.vue\";\nimport SignUp from \"@/pages/auth/SignUp.vue\";\nimport SignOut from \"@/pages/auth/SignOut.vue\";\nimport ConfirmSignUp from \"@/pages/auth/ConfirmSignUp.vue\";\nimport PasswordReset from \"@/pages/auth/PasswordReset.vue\";\nimport ChangePassword from \"@/pages/auth/ChangePassword.vue\";\nimport ConfirmPasswordReset from \"@/pages/auth/ConfirmPasswordReset.vue\";\n\nimport store from \"@/store\";\n\nVue.use(Router);\n\nconst routes = [\n  {\n    path: \"/\",\n    name: \"home\",\n    component: Home,\n    meta: { title: \"Home\", auth: false }\n  },\n  {\n    path: \"/dashboard\",\n    name: \"dashboard\",\n    component: Dashboard,\n    meta: { title: \"Dashboard\", auth: true }\n  },\n  {\n    path: \"/signIn\",\n    name: \"signIn\",\n    component: SignIn,\n    meta: { title: \"Sign In\", auth: false }\n  },\n  {\n    path: \"/signOut\",\n    name: \"signOut\",\n    component: SignOut,\n    meta: { title: \"Sign Out\", auth: true }\n  },\n  {\n    path: \"/signUp\",\n    name: \"signUp\",\n    component: SignUp,\n    meta: { title: \"Sign Up\", auth: false }\n  },\n  {\n    path: \"/confirmSignUp\",\n    name: \"confirmSignUp\",\n    component: ConfirmSignUp,\n    meta: { title: \"Confirm SignUp\", auth: false }\n  },\n  {\n    path: \"/changePassword\",\n    name: \"changePassword\",\n    component: ChangePassword,\n    meta: { title: \"Change Password\", auth: true }\n  },\n  {\n    path: \"/passwordReset\",\n    name: \"passwordReset\",\n    component: PasswordReset,\n    meta: { title: \"Password Reset\", auth: false }\n  },\n  {\n    path: \"/confirmPasswordReset\",\n    name: \"confirmPasswordReset\",\n    component: ConfirmPasswordReset,\n    meta: { title: \"Confirm Password Reset\", auth: false }\n  }\n];\n\nconst router = new Router({ mode: \"history\", routes });\n\n// this routine will ensure that any pages marked as `auth` in the `meta` section are\n// protected from access by unauthenticated users.\nrouter.beforeEach((to, from, next) => {\n  // Use the page's router title to name the page\n  if (to.meta && to.meta.title) {\n    document.title = to.meta.title;\n  }\n\n  // is there a meta and auth attribute?\n  if (to.meta && to.meta.auth !== undefined) {\n    // if the page requires auth\n    if (to.meta.auth) {\n      // and we are authenticated?\n      if (store.getters[\"auth/isAuthenticated\"]) {\n        next(); // route normally\n        return;\n      }\n      // otherwise off to the sign in page\n      router.push({ name: \"signIn\" });\n      return;\n    }\n    // otherwise are we already authenticated?\n    if (store.getters[\"auth/isAuthenticated\"]) {\n      // yes we are, so off to dashboard\n      router.push({ name: \"dashboard\" });\n      return;\n    }\n    next(); // route normally\n    return;\n  }\n  next(); // route normally\n  return;\n});\n\nexport default router;\n"
  },
  {
    "path": "src/store/index.js",
    "content": "import Vue from \"vue\";\nimport Vuex from \"vuex\";\nimport createPersist from \"vuex-localstorage\";\n\nVue.use(Vuex);\n\n// Modules\nimport auth from \"./modules/auth\";\n\nconst debug = process.env.NODE_ENV !== \"production\";\n\nconst store = new Vuex.Store({\n  modules: {\n    auth\n  },\n  strict: debug,\n  plugins: [\n    createPersist({\n      namespace: \"cognito-vue-bootstrap\",\n      initialState: {},\n      // ONE_WEEK\n      expires: 7 * 24 * 60 * 60 * 1e3\n    })\n  ]\n});\n\nexport default store;\n"
  },
  {
    "path": "src/store/modules/auth.js",
    "content": "import Auth from \"@aws-amplify/auth\";\nimport Amplify from \"@aws-amplify/core\";\n\nconst Logger = Amplify.Logger;\nLogger.LOG_LEVEL = \"DEBUG\"; // to show detailed logs from Amplify library\nconst logger = new Logger(\"store:auth\");\n\n// initial state\nconst state = {\n  user: null,\n  isAuthenticated: false,\n  authenticationStatus: null\n};\n\nconst getters = {\n  authenticatedUser: state => state.user,\n  isAuthenticated: state => state.isAuthenticated,\n  authenticationStatus: state => {\n    return state.authenticationStatus\n      ? state.authenticationStatus\n      : { variant: \"secondary\" };\n  },\n  hasAuthenticationStatus: state => {\n    return !!state.authenticationStatus;\n  }\n};\n\nconst mutations = {\n  setAuthenticationError(state, err) {\n    logger.debug(\"auth error: {}\", err);\n    state.authenticationStatus = {\n      state: \"failed\",\n      message: err.message,\n      variant: \"danger\"\n    };\n  },\n  clearAuthenticationStatus: state => {\n    state.authenticationStatus = null;\n  },\n  setUserAuthenticated(state, user) {\n    state.user = user;\n    state.isAuthenticated = true;\n  },\n  clearAuthentication(state) {\n    state.user = null;\n    state.userId = null;\n    state.isAuthenticated = false;\n  }\n};\n\nconst actions = {\n  clearAuthenticationStatus: context => {\n    context.commit(\"clearAuthenticationStatus\", null);\n  },\n  signIn: async (context, params) => {\n    logger.debug(\"signIn for {}\", params.username);\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      const user = await Auth.signIn(params.username, params.password);\n      context.commit(\"setUserAuthenticated\", user);\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  signOut: async context => {\n    try {\n      await Auth.signOut();\n    } catch (err) {\n      logger.error(\"error during sign out: {}\", err);\n    }\n    context.commit(\"auth/clearAuthentication\", null, { root: true });\n  },\n  signUp: async (context, params) => {\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.signUp(params);\n      context.commit(\"auth/clearAuthentication\", null, { root: true });\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  confirmSignUp: async (context, params) => {\n    logger.debug(\"confirm signup for {}\", params.username);\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.confirmSignUp(params.username, params.code);\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  confirmResend: async (context, params) => {\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.resendSignUp(params.username);\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  passwordReset: async (context, params) => {\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.forgotPassword(params.username);\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  confirmPasswordReset: async (context, params) => {\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.forgotPasswordSubmit(\n        params.username,\n        params.code,\n        params.password\n      );\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  passwordResetResend: async (context, params) => {\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      await Auth.passwordResetResend(params.username);\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  },\n  passwordChange: async (context, params) => {\n    logger.debug(\"password change for {}\", context.state.user.username);\n    context.commit(\"auth/clearAuthenticationStatus\", null, { root: true });\n    try {\n      const user = await Auth.currentAuthenticatedUser();\n      await Auth.changePassword(\n        user,\n        params.currentPassword,\n        params.newPassword\n      );\n    } catch (err) {\n      context.commit(\"auth/setAuthenticationError\", err, { root: true });\n    }\n  }\n};\n\nexport default {\n  namespaced: true,\n  state,\n  getters,\n  actions,\n  mutations\n};\n"
  },
  {
    "path": "tests/unit/footer.spec.js",
    "content": "import { render } from '@testing-library/vue'\nimport Footer from \"@/components/Footer.vue\";\n\ndescribe(\"Footer.vue\", () => {\n  it(\"renders props.msg when passed\", () => {\n    const { getByText } = render(Footer)\n    getByText('© 2018 Company, Inc.')\n  });\n});\n"
  },
  {
    "path": "vue.config.js",
    "content": "// vue.config.js\nmodule.exports = {\n  transpileDependencies: [/\\bvue-awesome\\b/]\n};\n"
  }
]